[boot][kernel] Split programs into sections
To enable setting sections as NX or read-only, the boot program loader now loads programs as lists of sections, and the kernel args are updated accordingly. The kernel's loader now just takes a program pointer to iterate the sections. Also enable NX in IA32_EFER in the bootloader.
This commit is contained in:
@@ -37,8 +37,25 @@ find_acpi_table(uefi::system_table *st)
|
||||
return reinterpret_cast<void*>(acpi1_table);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
rdmsr(uint32_t addr)
|
||||
{
|
||||
uint32_t low, high;
|
||||
__asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
|
||||
return (static_cast<uint64_t>(high) << 32) | low;
|
||||
}
|
||||
|
||||
static void
|
||||
wrmsr(uint32_t addr, uint64_t value)
|
||||
{
|
||||
uint32_t low = value & 0xffffffff;
|
||||
uint32_t high = value >> 32;
|
||||
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
setup_cr4()
|
||||
setup_control_regs()
|
||||
{
|
||||
uint64_t cr4 = 0;
|
||||
asm volatile ( "mov %%cr4, %0" : "=r" (cr4) );
|
||||
@@ -49,6 +66,15 @@ setup_cr4()
|
||||
0x020000 | // Enable PCIDs
|
||||
0;
|
||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4) );
|
||||
|
||||
// Set up IA32_EFER
|
||||
constexpr uint32_t IA32_EFER = 0xC0000080;
|
||||
uint64_t efer = rdmsr(IA32_EFER);
|
||||
efer |=
|
||||
0x0001 | // Enable SYSCALL
|
||||
0x0800 | // Enable NX bit
|
||||
0;
|
||||
wrmsr(IA32_EFER, efer);
|
||||
}
|
||||
|
||||
} // namespace hw
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace hw {
|
||||
/// significant bit set to 1.
|
||||
void * find_acpi_table(uefi::system_table *st);
|
||||
|
||||
/// Enable CPU options in CR4 for the kernel starting state.
|
||||
void setup_cr4();
|
||||
/// Enable CPU options in CR4 etc for the kernel starting state.
|
||||
void setup_control_regs();
|
||||
|
||||
} // namespace hw
|
||||
} // namespace boot
|
||||
|
||||
@@ -87,6 +87,9 @@ load_program(
|
||||
|
||||
bs->set_mem(pages, total_size, 0);
|
||||
|
||||
program.base = prog_base;
|
||||
program.total_size = total_size;
|
||||
program.num_sections = 0;
|
||||
for (int i = 0; i < header->ph_num; ++i) {
|
||||
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
||||
const elf::program_header *pheader =
|
||||
@@ -95,14 +98,18 @@ load_program(
|
||||
if (pheader->type != elf::PT_LOAD)
|
||||
continue;
|
||||
|
||||
args::program_section §ion = program.sections[program.num_sections++];
|
||||
|
||||
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
||||
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
||||
|
||||
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
||||
section.phys_addr = reinterpret_cast<uintptr_t>(dest_start);
|
||||
section.virt_addr = pheader->vaddr;
|
||||
section.size = pheader->mem_size;
|
||||
section.type = static_cast<args::section_flags>(pheader->flags);
|
||||
}
|
||||
|
||||
program.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
||||
program.size = total_size;
|
||||
program.virt_addr = prog_base;
|
||||
program.entrypoint = header->entrypoint;
|
||||
}
|
||||
|
||||
|
||||
@@ -192,16 +192,20 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
||||
status_bar status {con.fb()}; // Switch to fb status display
|
||||
|
||||
args::program &kernel = args->programs[0];
|
||||
paging::map_pages(args, kernel.phys_addr, kernel.virt_addr, kernel.size);
|
||||
for (auto §ion : kernel.sections)
|
||||
if (section.size)
|
||||
paging::map_section(args, section);
|
||||
|
||||
kernel::entrypoint kentry =
|
||||
reinterpret_cast<kernel::entrypoint>(kernel.entrypoint);
|
||||
status.next();
|
||||
|
||||
|
||||
hw::setup_control_regs();
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
status.next();
|
||||
|
||||
change_pointer(args->pml4);
|
||||
hw::setup_cr4();
|
||||
status.next();
|
||||
|
||||
kentry(args);
|
||||
|
||||
@@ -15,7 +15,7 @@ using memory::page_size;
|
||||
using ::memory::pml4e_kernel;
|
||||
using ::memory::table_entries;
|
||||
|
||||
// Flags: 0 0 0 1 0 0 0 0 0 0 1 1 = 0x0103
|
||||
// Flags: 0 0 0 1 0 0 0 0 0 0 0 1 = 0x0101
|
||||
// IGN | | | | | | | | +- Present
|
||||
// | | | | | | | +--- Writeable
|
||||
// | | | | | | +----- Usermode access (supervisor only)
|
||||
@@ -26,7 +26,7 @@ using ::memory::table_entries;
|
||||
// | +---------------- PAT (determining memory type for page)
|
||||
// +------------------- Global
|
||||
/// Page table entry flags for entries pointing at a page
|
||||
constexpr uint16_t page_flags = 0x103;
|
||||
constexpr uint64_t page_flags = 0x101;
|
||||
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
||||
// | IGN | | | | | | | | +- Present
|
||||
@@ -40,7 +40,7 @@ constexpr uint16_t page_flags = 0x103;
|
||||
// | +------------------- Global
|
||||
// +---------------------------- PAT (determining memory type for page)
|
||||
/// Page table entry flags for entries pointing at a huge page
|
||||
constexpr uint16_t huge_page_flags = 0x183;
|
||||
constexpr uint64_t huge_page_flags = 0x18b;
|
||||
|
||||
// Flags: 0 0 0 0 0 0 0 0 0 0 1 1 = 0x0003
|
||||
// IGNORED | | | | | | | +- Present
|
||||
@@ -52,7 +52,7 @@ constexpr uint16_t huge_page_flags = 0x183;
|
||||
// | +-------------- Ignored
|
||||
// +---------------- Reserved 0 (Table pointer, not page)
|
||||
/// Page table entry flags for entries pointing at another table
|
||||
constexpr uint16_t table_flags = 0x003;
|
||||
constexpr uint64_t table_flags = 0x003;
|
||||
|
||||
/// Iterator over page table entries.
|
||||
template <unsigned D = 4>
|
||||
@@ -191,7 +191,7 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
||||
status_line status(L"Allocating initial page tables");
|
||||
|
||||
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
||||
static constexpr size_t extra_tables = 49; // number of extra pages
|
||||
static constexpr size_t extra_tables = 64; // number of extra pages
|
||||
|
||||
// number of pages for kernelspace PDs + PML4
|
||||
static constexpr size_t kernel_tables = pd_tables + 1;
|
||||
@@ -223,23 +223,39 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
||||
console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr bool has_flag(E set, E flag) {
|
||||
return
|
||||
(static_cast<uint64_t>(set) & static_cast<uint64_t>(flag)) ==
|
||||
static_cast<uint64_t>(flag);
|
||||
}
|
||||
|
||||
void
|
||||
map_pages(
|
||||
map_section(
|
||||
kernel::args::header *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t size)
|
||||
const kernel::args::program_section §ion)
|
||||
{
|
||||
paging::page_table *pml4 =
|
||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
|
||||
size_t pages = memory::bytes_to_pages(size);
|
||||
size_t pages = memory::bytes_to_pages(section.size);
|
||||
page_entry_iterator<4> iterator{
|
||||
virt, pml4,
|
||||
section.virt_addr, pml4,
|
||||
args->page_tables,
|
||||
args->table_count};
|
||||
|
||||
using kernel::args::section_flags;
|
||||
|
||||
uint64_t flags = page_flags;
|
||||
if (!has_flag(section.type, section_flags::execute))
|
||||
flags |= (1ull << 63); // set NX bit
|
||||
|
||||
if (has_flag(section.type, section_flags::write))
|
||||
flags |= 2;
|
||||
|
||||
uintptr_t phys = section.phys_addr;
|
||||
while (true) {
|
||||
*iterator = phys | page_flags;
|
||||
*iterator = phys | flags;
|
||||
if (--pages == 0)
|
||||
break;
|
||||
|
||||
|
||||
@@ -38,15 +38,14 @@ void allocate_tables(
|
||||
/// tables in the current PML4.
|
||||
void add_current_mappings(page_table *new_pml4);
|
||||
|
||||
/// Map a physical address to a virtual address in the given page tables.
|
||||
/// \arg args The kernel args header, used for the page table cache and pml4
|
||||
/// \arg phys The phyiscal address to map in
|
||||
/// \arg virt The virtual address to map in
|
||||
/// \arg size The size in bytes of the mapping
|
||||
void map_pages(
|
||||
/// Map a program section in physical memory to its virtual address in the
|
||||
/// given page tables.
|
||||
/// \arg args The kernel args header, used for the page table cache and pml4
|
||||
/// \arg section The program section to load
|
||||
void map_section(
|
||||
kernel::args::header *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t bytes);
|
||||
const kernel::args::program_section §ion);
|
||||
|
||||
|
||||
} // namespace paging
|
||||
} // namespace boot
|
||||
|
||||
Reference in New Issue
Block a user