bool present : 1 = true;
};
+template<typename... Ts>
+void assert(bool cond, const char* format, const Ts&... vs);
+
template<size_t interrupt_nb>
void enable_interrupts(const isr_info (&ISRs)[interrupt_nb], os::idt<interrupt_nb>& idt) {
os::assert(is_APIC_builtin(), "No builtin APIC.");
// Allocate memory for segment:
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++) {
- const auto indices = os::paging::calc_page_table_indices(program_header.p_vaddr + i * 0x1000);
- if (PML4T.contents[indices.pml4e].P == 0) {
- PML4T.contents[indices.pml4e] = {.P = 1, .R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0};
- const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
- 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 = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PDT_alloc = os::paging::page_allocator.allocate(1);
- set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr<os::paging::PDT>(PDT_alloc.ptr.get_phys_addr()));
- }
- 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 = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PT_alloc = os::paging::page_allocator.allocate(1);
- set_base_address(PDT.contents[indices.pde], os::phys_ptr<os::paging::PT>(PT_alloc.ptr.get_phys_addr()));
- }
- os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]);
- os::assert(PT.contents[indices.pe].P == 0, "Process segments' memory overlaps the same pages.");
- PT.contents[indices.pe] = {.P = 1, .R_W = (program_header.flags & 2) >> 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 0};
- const auto page_alloc = os::paging::page_allocator.allocate(1);
- set_page_base_address(PT.contents[indices.pe], os::phys_ptr<os::paging::page>(page_alloc.ptr.get_phys_addr()));
+ os::paging::setup_page(PML4T, program_header.p_vaddr + i * 0x1000, (program_header.flags & 2) >> 1, 1, true);
}
-
// Initialise memory for segment:
for (std::size_t i = 0; i < program_header.p_filesz; i++) {
program_header.p_vaddr[i] = os::phys_ptr<std::byte>(test_module.start_address.get_phys_addr())[program_header.p_offset + i];
constexpr std::size_t stack_size = 16 * 0x1000 /* 64KiB */;
std::byte * const stack = (std::byte*)0x0000'8000'0000'0000 - stack_size;
for (std::size_t i = 0; i < stack_size / 0x1000 /* 64KiB */; i++) {
- const auto indices = os::paging::calc_page_table_indices(stack + i * 0x1000);
- os::assert(indices.pml4e < 256, "Userspace program must be in the lower-half of virtual memory.");
- if (PML4T.contents[indices.pml4e].P == 0) {
- PML4T.contents[indices.pml4e] = {.P = 1, .R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0};
- const auto PDPT_alloc = os::paging::page_allocator.allocate(1);
- 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 = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PDT_alloc = os::paging::page_allocator.allocate(1);
- set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr<os::paging::PDT>(PDT_alloc.ptr.get_phys_addr()));
- }
- 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 = 1, .PWT = 0, .PCD = 0, .base_address = 0, .NX = 0}};
- const auto PT_alloc = os::paging::page_allocator.allocate(1);
- set_base_address(PDT.contents[indices.pde], os::phys_ptr<os::paging::PT>(PT_alloc.ptr.get_phys_addr()));
- }
- os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]);
- os::assert(PT.contents[indices.pe].P == 0, "Process segments' memory overlaps the same pages.");
- PT.contents[indices.pe] = {.P = 1, .R_W = 1, .U_S = 1, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 0};
- const auto page_alloc = os::paging::page_allocator.allocate(1);
- set_page_base_address(PT.contents[indices.pe], os::phys_ptr<os::paging::page>(page_alloc.ptr.get_phys_addr()));
- }
-
- // Initialise stack to 0.
- for (std::size_t i = 0; i < stack_size; i++) {
- stack[i] = std::byte(0);
+ os::paging::setup_page(PML4T, stack + i * 0x1000, 1, 1, true);
}
asm volatile("invlpg (%0)" ::"r" (0x1000) : "memory");
#include "paging.hpp"
#include "serial.hpp"
+void os::paging::setup_page(os::paging::PML4T& PML4T, const void* vaddr, bool R_W, bool U_S, bool must_be_unmapped) {
+ const auto indices = os::paging::calc_page_table_indices(vaddr);
+ if (PML4T.contents[indices.pml4e].P == 0) {
+ PML4T.contents[indices.pml4e] = {.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);
+ 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);
+ set_base_address(PDPT.contents[indices.pdpe], os::phys_ptr<os::paging::PDT>(PDT_alloc.ptr.get_phys_addr()));
+ }
+ 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);
+ set_base_address(PDT.contents[indices.pde], os::phys_ptr<os::paging::PT>(PT_alloc.ptr.get_phys_addr()));
+ }
+ os::paging::PT& PT = *get_base_address(PDT.contents[indices.pde]);
+ if (PT.contents[indices.pe].P == 0) {
+ PT.contents[indices.pe] = {.P = 1, .R_W = R_W, .U_S = U_S, .PWT = 0, .PCD = 0, .PAT = 0, .G = 0, .base_address = 0, .NX = 0};
+ const auto page_alloc = os::paging::page_allocator.allocate(1);
+ set_page_base_address(PT.contents[indices.pe], os::phys_ptr<os::paging::page>(page_alloc.ptr.get_phys_addr()));
+ } else {
+ os::assert(!must_be_unmapped, "Memory at address 0x{} has already been mapped.", std::uintptr_t(vaddr));
+ }
+}
+
namespace {
void on_all_pages(const os::paging::PT& PT, void f(os::paging::page*, os::phys_ptr<os::paging::page>, std::size_t), std::size_t PT_virt_address) {
for (std::size_t i = 0; i < 512; i++) {
};
}
+void setup_page(PML4T& PML4T, const void* vaddr, bool R_W, bool U_S, bool must_be_unmapped);
+
// 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*, phys_ptr<page>, std::size_t));
// not, see <https://www.gnu.org/licenses/>.
#include <cstddef>
-#include "serial.hpp"
#include "utils.hpp"
#include "interrupts.hpp"
+#include "serial.hpp"
bool os::init_serial_port() {
outb(serial_port + 1, 0x00); // Disable interrupts.
os::print_formatted(format, std::uint64_t(val));
}
}
-void os::assert(bool cond, const char* diagnostic) {
- if (!cond) {
- os::print("Error: {}\n", diagnostic);
- os::cli();
- while (true) { os::hlt(); }
- }
-}
namespace os {
+template<typename... Ts>
+void assert(bool cond, const char* format, const Ts&... vs);
+
constexpr std::uint16_t serial_port{0x3F8};
bool init_serial_port();
bool serial_transmit_empty();
void write_serial(std::uint8_t v);
-void assert(bool cond, const char* diagnostic);
-
void printc(char c);
void print_formatted(const char* format, const char* val);
void print_formatted(const char* format, std::uint64_t val);
if (format[i] == '{') {
i++;
if (format[i] == '\0') {
- os::assert(false, "Error in format string: unterminated '{}'.");
+ os::assert(false, "Error in format string: unterminated '{{}'.");
} else if (format[i] == '{') {
printc('{');
continue;
std::size_t format_spec_end = i;
while (format[format_spec_end] != '}') {
if (format[format_spec_end++] == '\0') {
- os::assert(false, "Error in format string: unterminated '{}'.");
+ os::assert(false, "Error in format string: unterminated '{{}'.");
}
}
std::size_t n = arg_n;
arg_n++;
}
} else if (format[i] == '}') {
- os::assert(format[i + 1] == '}', "Error in format strin: unexpected '}'.");
+ os::assert(format[i + 1] == '}', "Error in format string: unexpected '}'.");
i++;
printc('}');
} else {
}
}
+void cli();
+void hlt();
+
+template<typename... Ts>
+void assert(bool cond, const char* format, const Ts&... vs) {
+ if (!cond) {
+ print("Error: ");
+ print(format, vs...);
+ printc('\n');
+ cli();
+ while (true) { hlt(); }
+ }
+}
+
} // namespace os