mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-08-04 01:36:10 -04:00
Try for user mode
This commit is contained in:
parent
6054bf8a06
commit
0afba27e41
4
Makefile
4
Makefile
@ -38,7 +38,9 @@ qemu: default
|
|||||||
qemu-kvm -cpu host -vga std -hda hdd.img
|
qemu-kvm -cpu host -vga std -hda hdd.img
|
||||||
|
|
||||||
bochs: default
|
bochs: default
|
||||||
bochs -qf bochsrc.txt
|
echo "c" > commands
|
||||||
|
bochs -qf bochsrc.txt -rc commands
|
||||||
|
rm commands
|
||||||
|
|
||||||
debug: default
|
debug: default
|
||||||
echo "c" > commands
|
echo "c" > commands
|
||||||
|
@ -17,8 +17,8 @@ namespace gdt {
|
|||||||
constexpr const uint16_t CODE_SELECTOR = 0x08;
|
constexpr const uint16_t CODE_SELECTOR = 0x08;
|
||||||
constexpr const uint16_t DATA_SELECTOR = 0x10;
|
constexpr const uint16_t DATA_SELECTOR = 0x10;
|
||||||
constexpr const uint16_t LONG_SELECTOR = 0x18;
|
constexpr const uint16_t LONG_SELECTOR = 0x18;
|
||||||
constexpr const uint16_t USER_DATA_SELECTOR = 0x20;
|
constexpr const uint16_t USER_CODE_SELECTOR = 0x20;
|
||||||
constexpr const uint16_t USER_CODE_SELECTOR = 0x28;
|
constexpr const uint16_t USER_DATA_SELECTOR = 0x28;
|
||||||
constexpr const uint16_t TSS_SELECTOR = 0x30;
|
constexpr const uint16_t TSS_SELECTOR = 0x30;
|
||||||
|
|
||||||
//Selector types
|
//Selector types
|
||||||
|
@ -14,6 +14,14 @@ namespace paging {
|
|||||||
|
|
||||||
constexpr const int PAGE_SIZE = 4096;
|
constexpr const int PAGE_SIZE = 4096;
|
||||||
|
|
||||||
|
//Flags
|
||||||
|
constexpr const uint8_t PRESENT = 0x1;
|
||||||
|
constexpr const uint8_t WRITE = 0x2;
|
||||||
|
constexpr const uint8_t USER = 0x4;
|
||||||
|
constexpr const uint8_t WRITE_THROUGH = 0x8;
|
||||||
|
constexpr const uint8_t CACHE_DISABLED = 0x10;
|
||||||
|
constexpr const uint8_t ACCESSED= 0x20;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool page_aligned(T* addr){
|
constexpr bool page_aligned(T* addr){
|
||||||
return !(reinterpret_cast<uintptr_t>(addr) & (paging::PAGE_SIZE - 1));
|
return !(reinterpret_cast<uintptr_t>(addr) & (paging::PAGE_SIZE - 1));
|
||||||
@ -28,14 +36,14 @@ void* physical_address(void* virt);
|
|||||||
bool page_present(void* virt);
|
bool page_present(void* virt);
|
||||||
bool page_free_or_set(void* virt, void* physical);
|
bool page_free_or_set(void* virt, void* physical);
|
||||||
|
|
||||||
bool identity_map(void* virt);
|
bool identity_map(void* virt, uint8_t flags = PRESENT | WRITE);
|
||||||
bool identity_map(void* virt, size_t pages);
|
bool identity_map_pages(void* virt, size_t pages, uint8_t flags = PRESENT | WRITE);
|
||||||
|
|
||||||
bool map(void* virt, void* physical);
|
bool map(void* virt, void* physical, uint8_t flags = PRESENT | WRITE);
|
||||||
bool map(void* virt, void* physical, size_t pages);
|
bool map_pages(void* virt, void* physical, size_t pages, uint8_t flags = PRESENT | WRITE);
|
||||||
|
|
||||||
bool unmap(void* virt);
|
bool unmap(void* virt);
|
||||||
bool unmap(void* virt, size_t pages);
|
bool unmap_pages(void* virt, size_t pages);
|
||||||
|
|
||||||
} //end of namespace paging
|
} //end of namespace paging
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ int init_acpi(){
|
|||||||
aligned_ptr = reinterpret_cast<unsigned int*>(reinterpret_cast<uintptr_t>(ptr) & ~(paging::PAGE_SIZE - 1));
|
aligned_ptr = reinterpret_cast<unsigned int*>(reinterpret_cast<uintptr_t>(ptr) & ~(paging::PAGE_SIZE - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!paging::identity_map(aligned_ptr, 2)){
|
if(!paging::identity_map_pages(aligned_ptr, 2)){
|
||||||
k_print_line("Impossible to identity map the ACPI tables");
|
k_print_line("Impossible to identity map the ACPI tables");
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -141,6 +141,10 @@ void setup_vesa(){
|
|||||||
vesa::vbe_info_block.signature[2] = 'E';
|
vesa::vbe_info_block.signature[2] = 'E';
|
||||||
vesa::vbe_info_block.signature[3] = '2';
|
vesa::vbe_info_block.signature[3] = '2';
|
||||||
|
|
||||||
|
vesa::vesa_enabled = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
uint16_t return_code;
|
uint16_t return_code;
|
||||||
asm volatile ("int 0x10"
|
asm volatile ("int 0x10"
|
||||||
: "=a"(return_code)
|
: "=a"(return_code)
|
||||||
@ -336,7 +340,7 @@ gdt::gdt_descriptor_t user_data_descriptor(){
|
|||||||
descriptor.limit_low = 0xFFFF;
|
descriptor.limit_low = 0xFFFF;
|
||||||
descriptor.limit_high = 0xF;
|
descriptor.limit_high = 0xF;
|
||||||
descriptor.always_1 = 1;
|
descriptor.always_1 = 1;
|
||||||
descriptor.dpl = 0;
|
descriptor.dpl = 3;
|
||||||
descriptor.present = 1;
|
descriptor.present = 1;
|
||||||
descriptor.avl = 0;
|
descriptor.avl = 0;
|
||||||
descriptor.big = 0;
|
descriptor.big = 0;
|
||||||
@ -360,8 +364,8 @@ void setup_gdt(){
|
|||||||
gdt[1] = code_32_descriptor();
|
gdt[1] = code_32_descriptor();
|
||||||
gdt[2] = data_descriptor();
|
gdt[2] = data_descriptor();
|
||||||
gdt[3] = code_64_descriptor();
|
gdt[3] = code_64_descriptor();
|
||||||
gdt[4] = user_data_descriptor();
|
gdt[4] = user_code_64_descriptor();
|
||||||
gdt[5] = user_code_64_descriptor();
|
gdt[5] = user_data_descriptor();
|
||||||
|
|
||||||
//2. Init TSS Descriptor
|
//2. Init TSS Descriptor
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ uint64_t* allocate_block(uint64_t blocks){
|
|||||||
|
|
||||||
auto block = reinterpret_cast<uint64_t*>(current_mmap_entry_position);
|
auto block = reinterpret_cast<uint64_t*>(current_mmap_entry_position);
|
||||||
|
|
||||||
paging::identity_map(block, blocks);
|
paging::identity_map_pages(block, blocks);
|
||||||
|
|
||||||
current_mmap_entry_position += blocks * BLOCK_SIZE;
|
current_mmap_entry_position += blocks * BLOCK_SIZE;
|
||||||
|
|
||||||
|
@ -18,10 +18,6 @@ typedef pt_t* pdt_t;
|
|||||||
typedef pdt_t* pdpt_t;
|
typedef pdt_t* pdpt_t;
|
||||||
typedef pdpt_t* pml4t_t;
|
typedef pdpt_t* pml4t_t;
|
||||||
|
|
||||||
constexpr const uint8_t PRESENT = 0x1;
|
|
||||||
constexpr const uint8_t WRITEABLE = 0x2;
|
|
||||||
constexpr const uint8_t USER = 0x4;
|
|
||||||
|
|
||||||
//Memory from 0x70000 can be used for pages
|
//Memory from 0x70000 can be used for pages
|
||||||
uintptr_t last_page = 0x73000;
|
uintptr_t last_page = 0x73000;
|
||||||
|
|
||||||
@ -101,7 +97,7 @@ bool paging::page_free_or_set(void* virt, void* physical){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paging::map(void* virt, void* physical){
|
bool paging::map(void* virt, void* physical, uint8_t flags){
|
||||||
//The address must be page-aligned
|
//The address must be page-aligned
|
||||||
if(!page_aligned(virt)){
|
if(!page_aligned(virt)){
|
||||||
return false;
|
return false;
|
||||||
@ -117,21 +113,21 @@ bool paging::map(void* virt, void* physical){
|
|||||||
|
|
||||||
//Init new page if necessary
|
//Init new page if necessary
|
||||||
if(!(reinterpret_cast<uintptr_t>(pml4t[pml4]) & PRESENT)){
|
if(!(reinterpret_cast<uintptr_t>(pml4t[pml4]) & PRESENT)){
|
||||||
pml4t[pml4] = reinterpret_cast<pdpt_t>(init_new_page() | (PRESENT | WRITEABLE));
|
pml4t[pml4] = reinterpret_cast<pdpt_t>(init_new_page() | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
|
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
|
||||||
|
|
||||||
//Init new page if necessary
|
//Init new page if necessary
|
||||||
if(!(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & PRESENT)){
|
if(!(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & PRESENT)){
|
||||||
pdpt[directory_ptr] = reinterpret_cast<pdt_t>(init_new_page() | (PRESENT | WRITEABLE));
|
pdpt[directory_ptr] = reinterpret_cast<pdt_t>(init_new_page() | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
|
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
|
||||||
|
|
||||||
//Init new page if necessary
|
//Init new page if necessary
|
||||||
if(!(reinterpret_cast<uintptr_t>(pdt[directory]) & PRESENT)){
|
if(!(reinterpret_cast<uintptr_t>(pdt[directory]) & PRESENT)){
|
||||||
pdt[directory] = reinterpret_cast<pt_t>(init_new_page() | (PRESENT | WRITEABLE));
|
pdt[directory] = reinterpret_cast<pt_t>(init_new_page() | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
|
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
|
||||||
@ -140,11 +136,11 @@ bool paging::map(void* virt, void* physical){
|
|||||||
if(reinterpret_cast<uintptr_t>(pt[table]) & PRESENT){
|
if(reinterpret_cast<uintptr_t>(pt[table]) & PRESENT){
|
||||||
//If the page is already set to the correct value, return true
|
//If the page is already set to the correct value, return true
|
||||||
//If the page is set to another value, return false
|
//If the page is set to another value, return false
|
||||||
return reinterpret_cast<uintptr_t>(pt[table]) == (reinterpret_cast<uintptr_t>(physical) | (PRESENT | WRITEABLE));
|
return reinterpret_cast<uintptr_t>(pt[table]) == (reinterpret_cast<uintptr_t>(physical) | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Map to the physical address
|
//Map to the physical address
|
||||||
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(physical) | (PRESENT | WRITEABLE));
|
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(physical) | flags);
|
||||||
|
|
||||||
//Flush TLB
|
//Flush TLB
|
||||||
flush_tlb(virt);
|
flush_tlb(virt);
|
||||||
@ -152,7 +148,7 @@ bool paging::map(void* virt, void* physical){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paging::map(void* virt, void* physical, size_t pages){
|
bool paging::map_pages(void* virt, void* physical, size_t pages, uint8_t flags){
|
||||||
//The address must be page-aligned
|
//The address must be page-aligned
|
||||||
if(!page_aligned(virt)){
|
if(!page_aligned(virt)){
|
||||||
return false;
|
return false;
|
||||||
@ -174,7 +170,7 @@ bool paging::map(void* virt, void* physical, size_t pages){
|
|||||||
auto virt_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(virt) + page * PAGE_SIZE);
|
auto virt_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(virt) + page * PAGE_SIZE);
|
||||||
auto phys_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(physical) + page * PAGE_SIZE);
|
auto phys_addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(physical) + page * PAGE_SIZE);
|
||||||
|
|
||||||
if(!map(virt_addr, phys_addr)){
|
if(!map(virt_addr, phys_addr, flags)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +222,7 @@ bool paging::unmap(void* virt){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paging::unmap(void* virt, size_t pages){
|
bool paging::unmap_pages(void* virt, size_t pages){
|
||||||
//The address must be page-aligned
|
//The address must be page-aligned
|
||||||
if(!page_aligned(virt)){
|
if(!page_aligned(virt)){
|
||||||
return false;
|
return false;
|
||||||
@ -244,10 +240,10 @@ bool paging::unmap(void* virt, size_t pages){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paging::identity_map(void* virt){
|
bool paging::identity_map(void* virt, uint8_t flags){
|
||||||
return map(virt, virt);
|
return map(virt, virt, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paging::identity_map(void* virt, size_t pages){
|
bool paging::identity_map_pages(void* virt, size_t pages, uint8_t flags){
|
||||||
return map(virt, virt, pages);
|
return map_pages(virt, virt, pages, flags);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "rtc.hpp"
|
#include "rtc.hpp"
|
||||||
#include "elf.hpp"
|
#include "elf.hpp"
|
||||||
#include "paging.hpp"
|
#include "paging.hpp"
|
||||||
|
#include "gdt.hpp"
|
||||||
#include "vesa.hpp"
|
#include "vesa.hpp"
|
||||||
|
|
||||||
//Commands
|
//Commands
|
||||||
@ -743,7 +744,7 @@ std::optional<std::string> read_elf_file(const std::string& file, const std::str
|
|||||||
return {std::move(content)};
|
return {std::move(content)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allocate_segments(char* buffer, void** allocated_segments){
|
bool allocate_segments(char* buffer, void** allocated_segments, uint8_t flags){
|
||||||
auto header = reinterpret_cast<elf::elf_header*>(buffer);
|
auto header = reinterpret_cast<elf::elf_header*>(buffer);
|
||||||
auto program_header_table = reinterpret_cast<elf::program_header*>(buffer + header->e_phoff);
|
auto program_header_table = reinterpret_cast<elf::program_header*>(buffer + header->e_phoff);
|
||||||
|
|
||||||
@ -793,7 +794,7 @@ bool allocate_segments(char* buffer, void** allocated_segments){
|
|||||||
|
|
||||||
//4. Map physical allocated memory to the necessary virtual memory
|
//4. Map physical allocated memory to the necessary virtual memory
|
||||||
|
|
||||||
if(!paging::map(reinterpret_cast<void*>(first_page), aligned_memory, pages)){
|
if(!paging::map_pages(reinterpret_cast<void*>(first_page), aligned_memory, pages, flags)){
|
||||||
k_print_line("Mapping the pages failed");
|
k_print_line("Mapping the pages failed");
|
||||||
failed = true;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
@ -810,6 +811,51 @@ bool allocate_segments(char* buffer, void** allocated_segments){
|
|||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* allocate_user_stack(size_t stack_address, size_t stack_size, uint8_t flags){
|
||||||
|
//0. Calculate some stuff
|
||||||
|
auto address = stack_address;
|
||||||
|
auto first_page = reinterpret_cast<uintptr_t>(paging::page_align(reinterpret_cast<void*>(address)));
|
||||||
|
auto left_padding = address - first_page;
|
||||||
|
auto bytes = left_padding + paging::PAGE_SIZE + stack_size;
|
||||||
|
auto pages = (bytes / paging::PAGE_SIZE) + 1;
|
||||||
|
|
||||||
|
//1. Verify that all the necessary pages are free
|
||||||
|
for(size_t i = 0; i < pages; ++i){
|
||||||
|
if(paging::page_present(reinterpret_cast<void*>(first_page + i * paging::PAGE_SIZE))){
|
||||||
|
k_print_line("Some pages are already mapped");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//2. Get enough physical memory
|
||||||
|
auto memory = k_malloc(bytes);
|
||||||
|
|
||||||
|
if(!memory){
|
||||||
|
k_print_line("Cannot allocate memory, probably out of memory");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//3. Find a start of a page inside the physical memory
|
||||||
|
|
||||||
|
auto aligned_memory = paging::page_aligned(memory) ? memory :
|
||||||
|
reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) / paging::PAGE_SIZE + 1) * paging::PAGE_SIZE);
|
||||||
|
|
||||||
|
//4. Map physical allocated memory to the necessary virtual memory
|
||||||
|
|
||||||
|
if(!paging::map_pages(reinterpret_cast<void*>(first_page), aligned_memory, pages, flags)){
|
||||||
|
k_print_line("Mapping the pages failed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//5. Zero-out memory
|
||||||
|
|
||||||
|
auto memory_start = reinterpret_cast<uintptr_t>(aligned_memory) + left_padding;
|
||||||
|
|
||||||
|
std::fill_n(reinterpret_cast<char*>(memory_start), stack_size, 0);
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
void release_segments(char* buffer, void** allocated_segments){
|
void release_segments(char* buffer, void** allocated_segments){
|
||||||
auto header = reinterpret_cast<elf::elf_header*>(buffer);
|
auto header = reinterpret_cast<elf::elf_header*>(buffer);
|
||||||
auto program_header_table = reinterpret_cast<elf::program_header*>(buffer + header->e_phoff);
|
auto program_header_table = reinterpret_cast<elf::program_header*>(buffer + header->e_phoff);
|
||||||
@ -828,7 +874,7 @@ void release_segments(char* buffer, void** allocated_segments){
|
|||||||
auto bytes = left_padding + paging::PAGE_SIZE + p_header.p_memsz;
|
auto bytes = left_padding + paging::PAGE_SIZE + p_header.p_memsz;
|
||||||
auto pages = (bytes / paging::PAGE_SIZE) + 1;
|
auto pages = (bytes / paging::PAGE_SIZE) + 1;
|
||||||
|
|
||||||
if(!paging::unmap(reinterpret_cast<void*>(first_page), pages)){
|
if(!paging::unmap_pages(reinterpret_cast<void*>(first_page), pages)){
|
||||||
k_print_line("Unmap failed, memory could be in invalid state");
|
k_print_line("Unmap failed, memory could be in invalid state");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -859,10 +905,26 @@ void exec_command(const std::vector<std::string>& params){
|
|||||||
|
|
||||||
std::unique_heap_array<void*> allocated_segments(header->e_phnum);
|
std::unique_heap_array<void*> allocated_segments(header->e_phnum);
|
||||||
|
|
||||||
auto failed = allocate_segments(buffer, allocated_segments.get());
|
auto failed = allocate_segments(buffer, allocated_segments.get(), paging::PRESENT | paging::WRITE | paging::USER);
|
||||||
|
|
||||||
if(!failed){
|
if(!failed){
|
||||||
//TODO
|
auto stack_physical = allocate_user_stack(0x500000, paging::PAGE_SIZE * 2, paging::PRESENT | paging::WRITE | paging::USER);
|
||||||
|
|
||||||
|
if(stack_physical){
|
||||||
|
asm volatile("mov ax, %0; mov ds, ax; mov es, ax; mov fs, ax; mov gs, ax;"
|
||||||
|
: //No outputs
|
||||||
|
: "i" (gdt::USER_DATA_SELECTOR + 3)
|
||||||
|
: "rax");
|
||||||
|
|
||||||
|
asm volatile("push %0; push %1; pushfq; push %2; push %3; iretq"
|
||||||
|
: //No outputs
|
||||||
|
: "i" (gdt::USER_DATA_SELECTOR + 3), "i" (0x500000 + paging::PAGE_SIZE * 2 - 64), "i" (gdt::USER_CODE_SELECTOR + 3), "r" (header->e_entry)
|
||||||
|
: "rax");
|
||||||
|
|
||||||
|
//TODO Release stack
|
||||||
|
} else {
|
||||||
|
k_print_line("Unable to allocate a stack for the program");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
k_print_line("execin: Unable to execute the program");
|
k_print_line("execin: Unable to execute the program");
|
||||||
}
|
}
|
||||||
@ -894,7 +956,7 @@ void execin_command(const std::vector<std::string>& params){
|
|||||||
|
|
||||||
std::unique_heap_array<void*> allocated_segments(header->e_phnum);
|
std::unique_heap_array<void*> allocated_segments(header->e_phnum);
|
||||||
|
|
||||||
auto failed = allocate_segments(buffer, allocated_segments.get());
|
auto failed = allocate_segments(buffer, allocated_segments.get(), paging::PRESENT | paging::WRITE);
|
||||||
|
|
||||||
if(!failed){
|
if(!failed){
|
||||||
auto main_function = reinterpret_cast<int(*)()>(header->e_entry);
|
auto main_function = reinterpret_cast<int(*)()>(header->e_entry);
|
||||||
|
@ -69,7 +69,7 @@ void vesa::init(){
|
|||||||
auto bytes = left_padding + paging::PAGE_SIZE + total_size;
|
auto bytes = left_padding + paging::PAGE_SIZE + total_size;
|
||||||
auto pages = (bytes / paging::PAGE_SIZE) + 1;
|
auto pages = (bytes / paging::PAGE_SIZE) + 1;
|
||||||
|
|
||||||
paging::identity_map(reinterpret_cast<void*>(first_page), pages);
|
paging::identity_map_pages(reinterpret_cast<void*>(first_page), pages);
|
||||||
|
|
||||||
init_font();
|
init_font();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user