or $1 << 7, %eax # PGE
mov %eax, %cr4
- # Set long mode bit:
+ # Set long mode bit (and NXE):
mov $0xC0000080, %ecx
rdmsr
or $1 << 8, %eax
+ or $1 << 11, %eax
wrmsr
# Enable paging:
mov %cr0, %eax
// Allocate, map and initialise memory for segment (memory above program_header.p_filesz is already 0-initialised by the page allocator):
std::size_t nb_pages = (std::uint64_t(program_header.p_vaddr) % 0x1000 + program_header.p_memsz + 0x1000 - 1) / 0x1000;
for (std::size_t i = 0; i < nb_pages; i++) {
- std::byte* const page =
- os::paging::setup_page(*result.PML4T, program_header.p_vaddr + i * 0x1000, (program_header.flags & 2) >> 1, 1);
- memcpy(page, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul));
+ auto const alloc = os::paging::page_allocator.allocate(1);
+ os::assert(alloc.ptr != nullptr, "Failed to allocate enough memory for loading of elf binary.");
+ os::paging::map_page(*result.PML4T, (os::paging::page<0>*)(program_header.p_vaddr + i * 0x1000), alloc.ptr,
+ {.R_W = (program_header.flags & 2) >> 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1 - (program_header.flags & 1)});
+ memcpy((void*)alloc.ptr, start + program_header.p_offset, clamp(0ul, program_header.p_filesz - i * 0x1000, 0x1000ul));
}
}
}
(0xFFFF'C000'0000'0000 <= vaddr && vaddr < 0xFFFF'C000'1000'0000) // process/port info
) { // Kernel memory
os::print("Allocating (Ring 0): {}\n", (void*)vaddr);
- os::paging::setup_page(os::paging::global_PML4T, (void*)vaddr, true, false);
+ auto const alloc = os::paging::page_allocator.allocate(1);
+ os::assert(alloc.ptr != nullptr, "Out of memory.");
+ os::paging::map_page(os::paging::global_PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
+ {.R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .PAT = 0, .G = 1, .base_address = 0, .NX = 1});
return;
} else if (
(0x0000'7FFF'FFFF'0000 <= vaddr && vaddr < 0x0000'8000'0000'0000) // stack
) { // Userspace memory
os::print("Allocating (Ring 3): {}\n", (void*)vaddr);
- os::paging::setup_page(*os::get_process(os::current_pid).PML4T, (void*)vaddr, true, true);
+ auto const alloc = os::paging::page_allocator.allocate(1);
+ os::assert(alloc.ptr != nullptr, "Out of memory.");
+ os::paging::map_page(*os::get_process(os::current_pid).PML4T, (os::paging::page<0>*)vaddr, alloc.ptr,
+ {.R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 1});
return;
}
os::print("Interrupt: Page Fault.\n");
extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
os::assert(magic == 0x36D76289, "Incorrect magic number: wasn't booted with multiboot2.");
+
+ os::paging::page_allocator.deallocate({
+ .ptr = os::phys_ptr<os::paging::page<0>>(reinterpret_cast<uintptr_t>(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000),
+ .size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0])
+ });
+
os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
// TODO: Initialise new PML4T
os::paging::global_PML4T = old_PML4T;
// /TODO
- os::print("a\n");
os::paging::load_pml4t(os::phys_ptr<os::paging::PML4T>{std::uintptr_t(&os::paging::global_PML4T) - 0xFFFF'FFFF'8000'0000});
- os::print("b\n");
if (!os::init_serial_port()) {
while (true) {
}
}
- os::paging::page_allocator.deallocate({
- .ptr = os::phys_ptr<os::paging::page<0>>(reinterpret_cast<uintptr_t>(bootstrap_pages_for_memory) - 0xFFFF'FFFF'8000'0000),
- .size = sizeof(bootstrap_pages_for_memory) / sizeof(bootstrap_pages_for_memory[0])
- });
-
{ // Enable interrupts really early so I don't have to manually manage memory... Will make better later, when I make utils.hpp/incrementing_int64_map better.
os::isr_info isr_info[32];
for (size_t i = 0; i < sizeof(isr_info) / sizeof(isr_info[0]); i++) {
// TODO: Not an emergency, but adapt in case we need multiple PML4Es. (*NOT* the case right now.)
static_assert(sizeof(os::processes) <= 1024 * 1024 * 1024, "Error: processes array too big.");
{
- const auto index = os::paging::calc_page_table_indices(&os::processes).pml4e;
+ std::size_t const index = (std::uint64_t(&os::processes) >> (12 + 9 * 3)) & 0x1FF;
os::paging::global_PML4T.contents[index] = {.non_page = {.P = 1, .R_W = 1, .U_S = 0, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
os::memset((void*)PDPT_alloc.ptr, 0, 0x1000);
os::paging::PML4T os::paging::global_PML4T;
-std::byte* os::paging::setup_page(os::paging::PML4T& PML4T, const void* vaddr, bool R_W, bool U_S) {
- const auto indices = os::paging::calc_page_table_indices(vaddr);
- if (PML4T.contents[indices.pml4e].non_page.P == 0) {
- PML4T.contents[indices.pml4e] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
- memset((void*)PDPT_alloc.ptr, 0, 0x1000);
- set_base_address(PML4T.contents[indices.pml4e], os::phys_ptr<os::paging::PDPT>(PDPT_alloc.ptr.get_phys_addr()));
- }
- os::paging::PDPT& PDPT = *get_base_address(PML4T.contents[indices.pml4e]);
- if (PDPT.contents[indices.pdpe].non_page.P == 0) {
- PDPT.contents[indices.pdpe] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PDT_alloc = os::paging::page_allocator.allocate(1);
- memset((void*)PDT_alloc.ptr, 0, 0x1000);
- set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr<os::paging::PDT>(PDT_alloc.ptr.get_phys_addr()));
- } else {
- assert(PDPT.contents[indices.pdpe].non_page.zero == 0,
- "Cannot map memory address 0x{} because it is inside a 1GiB page", std::uintptr_t(vaddr));
- }
- os::paging::PDT& PDT = *get_base_address(PDPT.contents[indices.pdpe]);
- if (PDT.contents[indices.pde].non_page.P == 0) {
- PDT.contents[indices.pde] = {.non_page = {.P = 1, .R_W = 1, .U_S = U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PT_alloc = os::paging::page_allocator.allocate(1);
- memset((void*)PT_alloc.ptr, 0, 0x1000);
- set_base_address(PDT.contents[indices.pde], os::phys_ptr<os::paging::PT>(PT_alloc.ptr.get_phys_addr()));
- } else {
- assert(PDT.contents[indices.pde].non_page.zero == 0,
- "Cannot map memory address 0x{} because it is inside a 2MiB page", std::uintptr_t(vaddr));
- }
- os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]);
- os::assert(PT.contents[indices.pe].page.P == 0, "Memory at address 0x{} has already been mapped.", std::uintptr_t(vaddr));
- PT.contents[indices.pe] =
- {.page = {.P = 1, .R_W = R_W, .U_S = U_S, .PWT = 0, .PCD = 0, .PAT = 0, .G = (indices.pml4e < 128) ? 0ul : 1ul, .base_address = 0, .NX = 0}};
- const auto page_alloc = os::paging::page_allocator.allocate(1);
- memset((void*)page_alloc.ptr, 0, 0x1000);
- set_page_base_address(PT.contents[indices.pe], os::phys_ptr<os::paging::page<0>>(page_alloc.ptr.get_phys_addr()));
- invlpg(vaddr);
- return (std::byte*)&*page_alloc.ptr;
-}
-
namespace {
void on_all_pages(const os::paging::PT& PT, void f(os::paging::page<0>*, os::phys_ptr<os::paging::page<0>>, std::size_t), std::size_t PT_virt_address) {
for (std::size_t i = 0; i < 512; i++) {
entry.page.base_address = ptr.get_phys_addr() / sizeof(page<depth>);
}
-struct page_table_indices {
- std::uint16_t pml4e;
- std::uint16_t pdpe;
- std::uint16_t pde;
- std::uint16_t pe;
-};
-constexpr page_table_indices calc_page_table_indices(const void* ptr) {
- return {
- .pml4e = std::uint16_t((std::uint64_t(ptr) >> 39) & 0x1FF),
- .pdpe = std::uint16_t((std::uint64_t(ptr) >> 30) & 0x1FF),
- .pde = std::uint16_t((std::uint64_t(ptr) >> 21) & 0x1FF),
- .pe = std::uint16_t((std::uint64_t(ptr) >> 12) & 0x1FF),
- };
-}
-
-std::byte* setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S);
+template <std::size_t depth, std::size_t paging_depth = 3>
+void map_page(paging_table<paging_depth>& paging_table, page<depth> const* vaddr, phys_ptr<page<depth>> phys_addr, decltype(paging_entry<depth>::page) page_info);
// For all present page mappings, calls f(virtual address, physical address, page size in bytes (4KiB, 2MiB or 1GiB)).
void on_all_pages(const PML4T& PML4T, void f(page<0>*, phys_ptr<page<0>>, std::size_t));
bool merge(phys_ptr<page> it);
};
+template <std::size_t depth, std::size_t paging_depth = 3>
+void map_page(paging_table<paging_depth>& paging_table, page<depth> const* vaddr, phys_ptr<page<depth>> phys_addr, decltype(paging_entry<depth>::page) page_info) {
+ std::size_t const index = (std::uint64_t(vaddr) >> (12 + 9 * paging_depth)) & 0x1FF;
+ if constexpr (depth == paging_depth) {
+ os::assert(paging_table.contents[index].page.P == 0, "Virtual address 0x{} is already mapped.", vaddr);
+ paging_table.contents[index].page = page_info;
+ paging_table.contents[index].page.P = 1;
+ set_page_base_address(paging_table.contents[index], phys_addr);
+ invlpg(vaddr);
+ } else {
+ if (paging_table.contents[index].non_page.P == 1) {
+ assert(!is_page(paging_table.contents[index]), "Virtual address 0x{} is already in a mapped page.", vaddr);
+ } else {
+ auto const alloc = page_allocator.allocate(1);
+ assert(alloc.ptr != nullptr, "Not enough RAM to create the paging structures.");
+ memset((void*)alloc.ptr, 0, 0x1000);
+ paging_table.contents[index].non_page = {.P = 1, .R_W = 1, .U_S = page_info.U_S, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0};
+ set_base_address(paging_table.contents[index], os::phys_ptr<os::paging::paging_table<paging_depth - 1>>{alloc.ptr.get_phys_addr()});
+ }
+ map_page<depth, paging_depth - 1>(*get_base_address(paging_table.contents[index]), vaddr, phys_addr, page_info);
+ }
+}
+
} } // namespace os::paging