Kernel: Add support for the NX bit
Not support, actually. We now REQUIRE it.
This commit is contained in:
parent
534500cda0
commit
22740e69bf
@ -10,4 +10,5 @@ namespace CPU
|
|||||||
uint64_t get_feature_bitmask();
|
uint64_t get_feature_bitmask();
|
||||||
uint64_t get_initial_apic_id();
|
uint64_t get_initial_apic_id();
|
||||||
bool has_feature(CPU::Features);
|
bool has_feature(CPU::Features);
|
||||||
|
bool has_nx();
|
||||||
}
|
}
|
@ -13,6 +13,8 @@ namespace MemoryManager
|
|||||||
{
|
{
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
void protect_kernel_sections();
|
||||||
|
|
||||||
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
|
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
|
||||||
void release_mapping(void* mapping);
|
void release_mapping(void* mapping);
|
||||||
|
|
||||||
|
@ -17,13 +17,17 @@ struct PageDirectoryEntry
|
|||||||
bool larger_pages : 1;
|
bool larger_pages : 1;
|
||||||
bool ignore1 : 1;
|
bool ignore1 : 1;
|
||||||
uint8_t available : 3;
|
uint8_t available : 3;
|
||||||
uint64_t address : 52;
|
uint64_t address : 48;
|
||||||
|
uint8_t available2 : 3;
|
||||||
|
bool no_execute : 1;
|
||||||
|
|
||||||
void set_address(uint64_t addr);
|
void set_address(uint64_t addr);
|
||||||
uint64_t get_address();
|
uint64_t get_address();
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct PageTable
|
struct PageTable
|
||||||
{
|
{
|
||||||
PageDirectoryEntry entries[512];
|
PageDirectoryEntry entries[512];
|
||||||
} __attribute__((aligned(PAGE_SIZE)));
|
} __attribute__((aligned(PAGE_SIZE)));
|
||||||
|
|
||||||
|
static_assert(sizeof(PageDirectoryEntry) == 8UL);
|
@ -33,6 +33,7 @@ namespace VMM
|
|||||||
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
|
PageDirectoryEntry* create_pde_if_not_exists(PageTable* root, uint64_t vaddr);
|
||||||
|
|
||||||
void propagate_read_write(PageTable* root, uint64_t vaddr);
|
void propagate_read_write(PageTable* root, uint64_t vaddr);
|
||||||
|
void propagate_no_execute(PageTable* root, uint64_t vaddr);
|
||||||
void propagate_user(PageTable* root, uint64_t vaddr);
|
void propagate_user(PageTable* root, uint64_t vaddr);
|
||||||
|
|
||||||
void flush_tlb(uint64_t addr);
|
void flush_tlb(uint64_t addr);
|
||||||
|
@ -16,14 +16,19 @@ SECTIONS
|
|||||||
kernel_start = .;
|
kernel_start = .;
|
||||||
.text : {
|
.text : {
|
||||||
KEEP(*(.text.boot)) *(.text .text.*) /* code */
|
KEEP(*(.text.boot)) *(.text .text.*) /* code */
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
start_of_kernel_rodata = .;
|
||||||
*(.rodata .rodata.*) /* data */
|
*(.rodata .rodata.*) /* data */
|
||||||
|
end_of_kernel_rodata = .;
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
start_of_kernel_data = .;
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
} :boot
|
} :boot
|
||||||
.bss (NOLOAD) : { /* bss */
|
.bss (NOLOAD) : { /* bss */
|
||||||
. = ALIGN(16);
|
|
||||||
*(.bss .bss.*)
|
*(.bss .bss.*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
} :boot
|
} :boot
|
||||||
|
end_of_kernel_data = .;
|
||||||
kernel_end = .;
|
kernel_end = .;
|
||||||
|
|
||||||
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
||||||
|
@ -66,6 +66,14 @@ uint64_t CPU::get_feature_bitmask()
|
|||||||
return bitmask;
|
return bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CPU::has_nx()
|
||||||
|
{
|
||||||
|
unsigned int unused;
|
||||||
|
unsigned int edx;
|
||||||
|
__get_cpuid(0x80000001, &unused, &unused, &unused, &edx);
|
||||||
|
return edx & (1 << 20);
|
||||||
|
}
|
||||||
|
|
||||||
static bool _has_feature(int feature)
|
static bool _has_feature(int feature)
|
||||||
{
|
{
|
||||||
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0;
|
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "std/assert.h"
|
#include "std/assert.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
#include "utils/Time.h"
|
#include "utils/Time.h"
|
||||||
|
#include "misc/MSR.h"
|
||||||
|
|
||||||
extern BOOTBOOT bootboot;
|
extern BOOTBOOT bootboot;
|
||||||
extern "C" char environment[4096];
|
extern "C" char environment[4096];
|
||||||
@ -39,6 +40,40 @@ void Init::disable_smp()
|
|||||||
extern "C" void asm_enable_sse();
|
extern "C" void asm_enable_sse();
|
||||||
extern void clock_init();
|
extern void clock_init();
|
||||||
|
|
||||||
|
extern void panic_prepare_keyboard_triple_fault();
|
||||||
|
|
||||||
|
#define NO_EXECUTE_ENABLED (1 << 11)
|
||||||
|
|
||||||
|
static void check_and_enable_nx()
|
||||||
|
{
|
||||||
|
if(!CPU::has_nx()) {
|
||||||
|
kerrorln("This machine does not support the NX feature, which is required to continue booting.");
|
||||||
|
kerrorln("On most cases, this means your machine is too old and not supported.");
|
||||||
|
|
||||||
|
kinfoln("Press any key to restart and select an OS that is suitable for your CPU.");
|
||||||
|
|
||||||
|
panic_prepare_keyboard_triple_fault();
|
||||||
|
|
||||||
|
while(1) halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
kdbgln("nx supported");
|
||||||
|
|
||||||
|
MSR efer(IA32_EFER_MSR);
|
||||||
|
|
||||||
|
uint64_t value = efer.read();
|
||||||
|
|
||||||
|
if(value & NO_EXECUTE_ENABLED)
|
||||||
|
{
|
||||||
|
kdbgln("nx already enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdbgln("nx not enabled, enabling it");
|
||||||
|
|
||||||
|
efer.write(value | NO_EXECUTE_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
void Init::early_init()
|
void Init::early_init()
|
||||||
{
|
{
|
||||||
Interrupts::disable();
|
Interrupts::disable();
|
||||||
@ -48,8 +83,12 @@ void Init::early_init()
|
|||||||
|
|
||||||
framebuffer0.init((void*)&fb, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width, bootboot.fb_height);
|
framebuffer0.init((void*)&fb, bootboot.fb_type, bootboot.fb_scanline, bootboot.fb_width, bootboot.fb_height);
|
||||||
|
|
||||||
|
check_and_enable_nx();
|
||||||
|
|
||||||
MemoryManager::init();
|
MemoryManager::init();
|
||||||
|
|
||||||
|
MemoryManager::protect_kernel_sections();
|
||||||
|
|
||||||
if (strstr(environment, "quiet=1"))
|
if (strstr(environment, "quiet=1"))
|
||||||
{
|
{
|
||||||
KernelLog::toggle_log_level(LogLevel::DEBUG);
|
KernelLog::toggle_log_level(LogLevel::DEBUG);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
#include "std/assert.h"
|
#include "std/assert.h"
|
||||||
|
#include "misc/utils.h"
|
||||||
|
|
||||||
void MemoryManager::init()
|
void MemoryManager::init()
|
||||||
{
|
{
|
||||||
@ -17,6 +18,17 @@ void MemoryManager::init()
|
|||||||
PMM::map_bitmap_to_virtual();
|
PMM::map_bitmap_to_virtual();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern char start_of_kernel_rodata[1];
|
||||||
|
extern char end_of_kernel_rodata[1];
|
||||||
|
extern char start_of_kernel_data[1];
|
||||||
|
extern char end_of_kernel_data[1];
|
||||||
|
|
||||||
|
void MemoryManager::protect_kernel_sections()
|
||||||
|
{
|
||||||
|
protect(start_of_kernel_rodata, Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_rodata - start_of_kernel_rodata), 0);
|
||||||
|
protect(start_of_kernel_data, Utilities::get_blocks_from_size(PAGE_SIZE, end_of_kernel_data - start_of_kernel_data), MAP_READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
void* MemoryManager::get_mapping(void* physicalAddress, int flags)
|
void* MemoryManager::get_mapping(void* physicalAddress, int flags)
|
||||||
{
|
{
|
||||||
uint64_t virtualAddress = KernelHeap::request_virtual_page();
|
uint64_t virtualAddress = KernelHeap::request_virtual_page();
|
||||||
|
@ -13,6 +13,8 @@ static PageTable* kernel_pml4;
|
|||||||
static PageTable* current_pml4;
|
static PageTable* current_pml4;
|
||||||
static AddressSpace* user_address_space;
|
static AddressSpace* user_address_space;
|
||||||
|
|
||||||
|
// FIXME: Switch to recursive paging instead of naively assuming the physical address space is identity mapped.
|
||||||
|
|
||||||
void VMM::switch_back_to_kernel_address_space()
|
void VMM::switch_back_to_kernel_address_space()
|
||||||
{
|
{
|
||||||
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
|
if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; }
|
||||||
@ -85,6 +87,9 @@ void VMM::remap(uint64_t vaddr, int flags)
|
|||||||
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
||||||
else
|
else
|
||||||
pde->read_write = false;
|
pde->read_write = false;
|
||||||
|
if(flags & Execute) pde->no_execute = false;
|
||||||
|
else
|
||||||
|
pde->no_execute = true;
|
||||||
flush_tlb(vaddr);
|
flush_tlb(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +109,7 @@ uint64_t VMM::get_flags(uint64_t vaddr)
|
|||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
if (pde->user) flags |= User;
|
if (pde->user) flags |= User;
|
||||||
if (pde->read_write) flags |= ReadWrite;
|
if (pde->read_write) flags |= ReadWrite;
|
||||||
|
if(!pde->no_execute) flags |= Execute;
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +136,9 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags)
|
|||||||
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr);
|
||||||
else
|
else
|
||||||
pde->read_write = false;
|
pde->read_write = false;
|
||||||
|
if(flags & Execute) pde->no_execute = false;
|
||||||
|
else
|
||||||
|
pde->no_execute = true;
|
||||||
if (will_flush_tlb) flush_tlb(vaddr);
|
if (will_flush_tlb) flush_tlb(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +255,34 @@ void VMM::propagate_user(PageTable* root, uint64_t vaddr)
|
|||||||
pde->user = true;
|
pde->user = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMM::propagate_no_execute(PageTable* root, uint64_t vaddr)
|
||||||
|
{
|
||||||
|
uint64_t page_index;
|
||||||
|
PageDirectoryEntry* pde;
|
||||||
|
PageTable* pt = root;
|
||||||
|
|
||||||
|
uint64_t indexes[3];
|
||||||
|
|
||||||
|
decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
pde = &pt->entries[indexes[i]];
|
||||||
|
if (!pde->present) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pde->no_execute = true;
|
||||||
|
if (pde->larger_pages) return;
|
||||||
|
pt = (PageTable*)pde->get_address();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pde = &pt->entries[page_index];
|
||||||
|
if (!pde->present) return;
|
||||||
|
else
|
||||||
|
pde->no_execute = true;
|
||||||
|
}
|
||||||
|
|
||||||
void VMM::flush_tlb(uint64_t addr)
|
void VMM::flush_tlb(uint64_t addr)
|
||||||
{
|
{
|
||||||
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
static bool g_is_in_panic = false;
|
static bool g_is_in_panic = false;
|
||||||
static bool g_is_in_double_panic = false;
|
static bool g_is_in_double_panic = false;
|
||||||
|
|
||||||
static void panic_prepare_keyboard_triple_fault()
|
void panic_prepare_keyboard_triple_fault()
|
||||||
{
|
{
|
||||||
PIC::enable_master(0b11111101); // enable keyboard only
|
PIC::enable_master(0b11111101); // enable keyboard only
|
||||||
PIC::enable_slave(0b11111111);
|
PIC::enable_slave(0b11111111);
|
||||||
|
@ -105,7 +105,11 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
|
|||||||
VMM::apply_address_space();
|
VMM::apply_address_space();
|
||||||
VMM::switch_to_previous_user_address_space();
|
VMM::switch_to_previous_user_address_space();
|
||||||
|
|
||||||
MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
|
int new_flags = MAP_USER;
|
||||||
|
if(phdr.p_flags & 2) new_flags |= MAP_READ_WRITE;
|
||||||
|
if(phdr.p_flags & 1) new_flags |= MAP_EXEC;
|
||||||
|
|
||||||
|
MemoryManager::protect(buffer, pages, new_flags);
|
||||||
|
|
||||||
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
|
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
|
||||||
(image->section_count + 1) * sizeof(ELFSection));
|
(image->section_count + 1) * sizeof(ELFSection));
|
||||||
|
@ -10,27 +10,35 @@
|
|||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define MAP_READ 1
|
#define PROT_READ 1
|
||||||
#define MAP_WRITE 2
|
#define PROT_WRITE 2
|
||||||
#define MAP_NONE 0
|
#define PROT_NONE 0
|
||||||
|
#define PROT_EXEC 4
|
||||||
|
|
||||||
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
||||||
|
|
||||||
static const char* format_prot(int prot)
|
static const char* format_prot(int prot)
|
||||||
{
|
{
|
||||||
static char prot_string[3];
|
static char prot_string[4];
|
||||||
prot_string[2] = 0;
|
prot_string[3] = 0;
|
||||||
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
|
prot_string[0] = ((prot & PROT_READ) > 0) ? 'r' : '-';
|
||||||
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
|
prot_string[1] = ((prot & PROT_WRITE) > 0) ? 'w' : '-';
|
||||||
|
prot_string[2] = ((prot & PROT_WRITE) > 0) ? 'x' : '-';
|
||||||
return prot_string;
|
return prot_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mman_flags_from_prot(int prot)
|
static int mman_flags_from_prot(int prot)
|
||||||
{
|
{
|
||||||
prot &= 0b11;
|
prot &= 0b111;
|
||||||
if (prot == MAP_NONE) return 0;
|
int flags = MAP_USER;
|
||||||
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
|
if (prot == PROT_NONE) return 0;
|
||||||
return MAP_USER;
|
if ((prot & PROT_WRITE) > 0) {
|
||||||
|
flags |= MAP_READ_WRITE;
|
||||||
|
}
|
||||||
|
if ((prot & PROT_EXEC) > 0) {
|
||||||
|
flags |= MAP_EXEC;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_mmap(Context* context, void* address, size_t size, int prot)
|
void sys_mmap(Context* context, void* address, size_t size, int prot)
|
||||||
|
Loading…
Reference in New Issue
Block a user