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_initial_apic_id();
|
||||
bool has_feature(CPU::Features);
|
||||
bool has_nx();
|
||||
}
|
@ -13,6 +13,8 @@ namespace MemoryManager
|
||||
{
|
||||
void init();
|
||||
|
||||
void protect_kernel_sections();
|
||||
|
||||
void* get_mapping(void* physicalAddress, int flags = MAP_READ_WRITE);
|
||||
void release_mapping(void* mapping);
|
||||
|
||||
|
@ -17,13 +17,17 @@ struct PageDirectoryEntry
|
||||
bool larger_pages : 1;
|
||||
bool ignore1 : 1;
|
||||
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);
|
||||
uint64_t get_address();
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PageTable
|
||||
{
|
||||
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);
|
||||
|
||||
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 flush_tlb(uint64_t addr);
|
||||
|
@ -16,14 +16,19 @@ SECTIONS
|
||||
kernel_start = .;
|
||||
.text : {
|
||||
KEEP(*(.text.boot)) *(.text .text.*) /* code */
|
||||
. = ALIGN(0x1000);
|
||||
start_of_kernel_rodata = .;
|
||||
*(.rodata .rodata.*) /* data */
|
||||
end_of_kernel_rodata = .;
|
||||
. = ALIGN(0x1000);
|
||||
start_of_kernel_data = .;
|
||||
*(.data .data.*)
|
||||
} :boot
|
||||
.bss (NOLOAD) : { /* bss */
|
||||
. = ALIGN(16);
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :boot
|
||||
end_of_kernel_data = .;
|
||||
kernel_end = .;
|
||||
|
||||
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
||||
|
@ -66,6 +66,14 @@ uint64_t CPU::get_feature_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)
|
||||
{
|
||||
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "std/assert.h"
|
||||
#include "std/string.h"
|
||||
#include "utils/Time.h"
|
||||
#include "misc/MSR.h"
|
||||
|
||||
extern BOOTBOOT bootboot;
|
||||
extern "C" char environment[4096];
|
||||
@ -39,6 +40,40 @@ void Init::disable_smp()
|
||||
extern "C" void asm_enable_sse();
|
||||
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()
|
||||
{
|
||||
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);
|
||||
|
||||
check_and_enable_nx();
|
||||
|
||||
MemoryManager::init();
|
||||
|
||||
MemoryManager::protect_kernel_sections();
|
||||
|
||||
if (strstr(environment, "quiet=1"))
|
||||
{
|
||||
KernelLog::toggle_log_level(LogLevel::DEBUG);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "memory/PMM.h"
|
||||
#include "memory/VMM.h"
|
||||
#include "std/assert.h"
|
||||
#include "misc/utils.h"
|
||||
|
||||
void MemoryManager::init()
|
||||
{
|
||||
@ -17,6 +18,17 @@ void MemoryManager::init()
|
||||
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)
|
||||
{
|
||||
uint64_t virtualAddress = KernelHeap::request_virtual_page();
|
||||
|
@ -13,6 +13,8 @@ static PageTable* kernel_pml4;
|
||||
static PageTable* current_pml4;
|
||||
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()
|
||||
{
|
||||
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);
|
||||
else
|
||||
pde->read_write = false;
|
||||
if(flags & Execute) pde->no_execute = false;
|
||||
else
|
||||
pde->no_execute = true;
|
||||
flush_tlb(vaddr);
|
||||
}
|
||||
|
||||
@ -104,6 +109,7 @@ uint64_t VMM::get_flags(uint64_t vaddr)
|
||||
uint64_t flags = 0;
|
||||
if (pde->user) flags |= User;
|
||||
if (pde->read_write) flags |= ReadWrite;
|
||||
if(!pde->no_execute) flags |= Execute;
|
||||
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);
|
||||
else
|
||||
pde->read_write = false;
|
||||
if(flags & Execute) pde->no_execute = false;
|
||||
else
|
||||
pde->no_execute = true;
|
||||
if (will_flush_tlb) flush_tlb(vaddr);
|
||||
}
|
||||
|
||||
@ -246,6 +255,34 @@ void VMM::propagate_user(PageTable* root, uint64_t vaddr)
|
||||
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)
|
||||
{
|
||||
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
||||
|
@ -16,7 +16,7 @@
|
||||
static bool g_is_in_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_slave(0b11111111);
|
||||
|
@ -105,7 +105,11 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
|
||||
VMM::apply_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->section_count + 1) * sizeof(ELFSection));
|
||||
|
@ -10,27 +10,35 @@
|
||||
#include "thread/Scheduler.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define MAP_READ 1
|
||||
#define MAP_WRITE 2
|
||||
#define MAP_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_NONE 0
|
||||
#define PROT_EXEC 4
|
||||
|
||||
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
|
||||
|
||||
static const char* format_prot(int prot)
|
||||
{
|
||||
static char prot_string[3];
|
||||
prot_string[2] = 0;
|
||||
prot_string[0] = ((prot & MAP_READ) > 0) ? 'r' : '-';
|
||||
prot_string[1] = ((prot & MAP_WRITE) > 0) ? 'w' : '-';
|
||||
static char prot_string[4];
|
||||
prot_string[3] = 0;
|
||||
prot_string[0] = ((prot & PROT_READ) > 0) ? 'r' : '-';
|
||||
prot_string[1] = ((prot & PROT_WRITE) > 0) ? 'w' : '-';
|
||||
prot_string[2] = ((prot & PROT_WRITE) > 0) ? 'x' : '-';
|
||||
return prot_string;
|
||||
}
|
||||
|
||||
static int mman_flags_from_prot(int prot)
|
||||
{
|
||||
prot &= 0b11;
|
||||
if (prot == MAP_NONE) return 0;
|
||||
if ((prot & MAP_WRITE) > 0) return MAP_USER | MAP_READ_WRITE;
|
||||
return MAP_USER;
|
||||
prot &= 0b111;
|
||||
int flags = MAP_USER;
|
||||
if (prot == PROT_NONE) return 0;
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user