From 4300f17832c47f0dc0e66e4f4700188a0e498a3a Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Wed, 17 Jan 2024 18:47:16 +1300 Subject: [PATCH 01/29] Read Me LOC --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d5744fee..bc95f7a1 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![Build][built-shield]][built-url] +[![Lines of Code][loc-shield]][loc-url]
@@ -239,4 +240,6 @@ Distributed under the BSD 3-Clause License. See `LICENSE` for more information. [issues-shield]: https://img.shields.io/github/issues/maxtyson123/MaxOS.svg?style=for-the-badge [issues-url]: https://github.com/maxtyson123/MaxOS/issues [built-shield]: https://img.shields.io/github/actions/workflow/status/maxtyson123/MaxOS/max-os.yml?style=for-the-badge -[built-url]: https://github.com/maxtyson123/MaxOS/actions/workflows/max-os.yml \ No newline at end of file +[built-url]: https://github.com/maxtyson123/MaxOS/actions/workflows/max-os.yml +[loc-shield]: https://img.shields.io/tokei/lines/github/maxtyson123/MaxOS?style=for-the-badge +[loc-url]: https://github.com/maxtyson123/MaxOS \ No newline at end of file From 0771f1187b14e09e59f428bc67ae84a2db3fca1c Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Wed, 17 Jan 2024 20:56:18 +1300 Subject: [PATCH 02/29] 64 Bit GDT --- kernel/include/system/gdt.h | 36 +--- .../src/hardwarecommunication/interrupts.cpp | 4 +- kernel/src/kernel.cpp | 9 +- kernel/src/system/gdt.cpp | 186 ++++++------------ kernel/src/system/multitasking.cpp | 2 +- kernel/src/system/multithreading.cpp | 2 +- toolchain/copy_filesystem.sh | 0 toolchain/create_disk_img.sh | 0 toolchain/make_cross_compiler.sh | 0 toolchain/make_documentation.sh | 0 toolchain/run_qemu.sh | 0 toolchain/version.sh | 0 12 files changed, 76 insertions(+), 163 deletions(-) mode change 100755 => 100644 toolchain/copy_filesystem.sh mode change 100755 => 100644 toolchain/create_disk_img.sh mode change 100755 => 100644 toolchain/make_cross_compiler.sh mode change 100755 => 100644 toolchain/make_documentation.sh mode change 100755 => 100644 toolchain/run_qemu.sh mode change 100755 => 100644 toolchain/version.sh diff --git a/kernel/include/system/gdt.h b/kernel/include/system/gdt.h index 6f68ea4f..2ea63d74 100644 --- a/kernel/include/system/gdt.h +++ b/kernel/include/system/gdt.h @@ -11,49 +11,23 @@ namespace MaxOS { namespace system { - /** - * @class SegmentDescriptor - * @brief Stores data for the segment descriptors in the GDT - */ - class SegmentDescriptor { - private: - uint16_t m_limit_lo; - uint16_t m_base_lo; - uint8_t m_base_hi; - uint8_t m_type; - uint8_t m_flags_limit_hi; - uint8_t m_base_vhi; - - public: - SegmentDescriptor(uint32_t base, uint32_t limit, uint8_t type); - - uint32_t base(); - uint32_t limit(); + struct GDTR { + uint16_t limit; + uint64_t address; } __attribute__((packed)); - /** * @class GlobalDescriptorTable * @brief Sets up the GDT in the CPU */ class GlobalDescriptorTable { - private: - SegmentDescriptor m_null_segment_selector; - SegmentDescriptor m_unused_segment_selector; - SegmentDescriptor m_code_segment_selector; - SegmentDescriptor m_data_segment_selector; - SegmentDescriptor m_task_state_segment_selector; + uint64_t m_gdt[4]; public: - - GlobalDescriptorTable(multiboot_tag_basic_meminfo* meminfo); + GlobalDescriptorTable(); ~GlobalDescriptorTable(); - - uint16_t code_segment_selector(); - uint16_t data_segment_selector(); - uint16_t task_state_segment_selector(); }; } } diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index 0fab059c..c962ea85 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -53,7 +53,9 @@ InterruptManager::InterruptManager(uint16_t hardware_interrupt_offset, system::G pic_slave_data_port(0xA1) { - uint32_t code_segment = global_descriptor_table->code_segment_selector(); + // TODO: Re write the IDT + return; + uint32_t code_segment = 0; // By default ignore all interrupts so any un handled interrupts wont cause a fault const uint8_t IDT_INTERRUPT_GATE = 0xE; diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index d06dad90..1fbdac12 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -111,8 +111,11 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("MaxOS booted\n"); - // TODO: Now that it is in a 64bit mode in the higher half some things need to be rewritten - while (true); + GlobalDescriptorTable gdt; + _kprintf("GDT set up\n"); + + // TODO: 64 bit architecture rewrite + return; // Make the multiboot header Multiboot multiboot(addr); @@ -157,7 +160,7 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) systemSetupHeaderStream << "Setting up system"; //Setup GDT - GlobalDescriptorTable gdt(multiboot.get_basic_meminfo()); + // TODO: GlobalDescriptorTable gdt; cout << "-- Set Up GDT\n"; systemSetupHeaderStream << "."; diff --git a/kernel/src/system/gdt.cpp b/kernel/src/system/gdt.cpp index e5bc8577..29333070 100644 --- a/kernel/src/system/gdt.cpp +++ b/kernel/src/system/gdt.cpp @@ -3,140 +3,74 @@ // #include +#include + using namespace MaxOS; using namespace MaxOS::system; - -/** - * @brief Constructor for Segment Selector - * - * - * @param base base address - * @param limit limit - * @param flags Flags - */ -SegmentDescriptor::SegmentDescriptor(uint32_t base, uint32_t limit, uint8_t type) -{ - uint8_t* target = (uint8_t*)this; //segment entry in GDT. - - if (limit <= 65536) - { - // 16-bit address space - target[6] = 0x40; - } - else - { - // 32-bit address space - if((limit & 0xFFF) != 0xFFF) - limit = (limit >> 12)-1; - else - limit = limit >> 12; - - target[6] = 0xC0; - } - - // Encode the limit - target[0] = limit & 0xFF; - target[1] = (limit >> 8) & 0xFF; - target[6] |= (limit >> 16) & 0xF; - - // Encode the base - target[2] = base & 0xFF; - target[3] = (base >> 8) & 0xFF; - target[4] = (base >> 16) & 0xFF; - target[7] = (base >> 24) & 0xFF; - - // Type / Access Rights - target[5] = type; -} -/** - * @brief Look up the pointer - * - * @return The pointer - */ -uint32_t SegmentDescriptor::base() -{ - uint8_t* target = (uint8_t*)this; - - uint32_t result = target[7]; - result = (result << 8) + target[4]; - result = (result << 8) + target[3]; - result = (result << 8) + target[2]; - - return result; -} - -/** - * @brief Look up the limit - * - * @return The limit - */ -uint32_t SegmentDescriptor::limit() +GlobalDescriptorTable::GlobalDescriptorTable() { - uint8_t* target = (uint8_t*)this; - uint32_t result = target[6] & 0xF; - result = (result << 8) + target[1]; - result = (result << 8) + target[0]; - - if((target[6] & 0xC0) == 0xC0) - result = (result << 12) | 0xFFF; - - return result; -} - -/** - * @brief Global Descriptor Table - */ -GlobalDescriptorTable::GlobalDescriptorTable(multiboot_tag_basic_meminfo* meminfo) -: m_null_segment_selector(0, 0, 0), m_unused_segment_selector(0, 0, 0), - m_code_segment_selector(0, 1024* meminfo -> mem_upper, 0x9A), - m_data_segment_selector(0, 1024* meminfo -> mem_upper, 0x92), - m_task_state_segment_selector(0, 1024* meminfo -> mem_upper, 0) - -{ - - // Create GDT - uint32_t gdt_t[2]; - gdt_t[0] = sizeof(GlobalDescriptorTable) << 16; - gdt_t[1] = (uint32_t)this; - - // Tell processor to use this table - asm volatile("lgdt (%0)": :"p" (((uint8_t *) gdt_t)+2)); + // Null descriptor + m_gdt[0] = 0; + + // Kernel code segment descriptor + uint64_t kernel_code_segment_descriptor = 0; + kernel_code_segment_descriptor |= 0b1011 << 8; // Type of selector + kernel_code_segment_descriptor |= 1 << 12; // Not a system descriptor + kernel_code_segment_descriptor |= 0 << 13; // Privilege level 0 + kernel_code_segment_descriptor |= 1 << 15; // Present + kernel_code_segment_descriptor |= 1 << 21; // Long mode + m_gdt[1] = kernel_code_segment_descriptor << 32; + + // Kernel data segment descriptor + uint64_t kernel_data_segment_descriptor = 0; + kernel_data_segment_descriptor |= 0b0011 << 8; // Type of selector + kernel_data_segment_descriptor |= 1 << 12; // Not a system descriptor + kernel_data_segment_descriptor |= 0 << 13; // Privilege level 0 + kernel_data_segment_descriptor |= 1 << 15; // Present + kernel_data_segment_descriptor |= 1 << 21; // Long mode + m_gdt[2] = kernel_data_segment_descriptor << 32; + + // User code segment descriptor (Change the privilege level to 3) + uint64_t user_code_segment_descriptor = kernel_code_segment_descriptor | (3 << 13); + m_gdt[3] = user_code_segment_descriptor; + + // User data segment descriptor (Change the privilege level to 3) + uint64_t user_data_segment_descriptor = kernel_data_segment_descriptor | (3 << 13); + m_gdt[4] = user_data_segment_descriptor; + + _kprintf("Created GDT entries\n"); + + // Store the GDT in the GDTR + GDTR gdtr = { + .limit = 4 * sizeof(uint64_t) - 1, + .address = (uint64_t)m_gdt + }; + + // Load the GDTR + asm volatile("lgdt %0" : : "m" (gdtr)); + + _kprintf("Loaded GDT\n"); + + // Reload the segment registers + asm volatile("\ + mov $0x10, %ax \n\ + mov %ax, %ds \n\ + mov %ax, %es \n\ + mov %ax, %fs \n\ + mov %ax, %gs \n\ + mov %ax, %ss \n\ + \n\ + pop %rdi \n\ + push $0x8 \n\ + push %rdi \n\ + "); + + _kprintf("Reloaded segment registers\n"); } GlobalDescriptorTable::~GlobalDescriptorTable() { -} - - -/** - * @brief Data Segment Selector - * - * @return The data segment selector offset - */ -uint16_t GlobalDescriptorTable::data_segment_selector() -{ - return (uint8_t*)&m_data_segment_selector - (uint8_t*)this; -} - -/** - * @brief Code Segment Selector - * - * @return The code segment selector offset - */ -uint16_t GlobalDescriptorTable::code_segment_selector() -{ - return (uint8_t*)&m_code_segment_selector - (uint8_t*)this; -} - -/** - * @brief Task State Segment Selector - * - * @return The task state segment selector offset - */ -uint16_t GlobalDescriptorTable::task_state_segment_selector() -{ - return (uint8_t*)&m_task_state_segment_selector - (uint8_t*)this; } \ No newline at end of file diff --git a/kernel/src/system/multitasking.cpp b/kernel/src/system/multitasking.cpp index 4d05f2ac..0976f463 100644 --- a/kernel/src/system/multitasking.cpp +++ b/kernel/src/system/multitasking.cpp @@ -28,7 +28,7 @@ Task::Task(GlobalDescriptorTable *gdt, void entrypoint()) { // Set up the function pointer m_cpu_state-> eip = (uint32_t)entrypoint; - m_cpu_state-> cs = gdt->code_segment_selector(); + //TODO: m_cpu_state-> cs = gdt->code_segment_selector(); m_cpu_state-> eflags = 0x202; } diff --git a/kernel/src/system/multithreading.cpp b/kernel/src/system/multithreading.cpp index 356685e0..61ca0853 100644 --- a/kernel/src/system/multithreading.cpp +++ b/kernel/src/system/multithreading.cpp @@ -62,7 +62,7 @@ uint32_t ThreadManager::create_thread(void entrypoint()) Thread* new_thread = new Thread(); new_thread -> init(entrypoint); new_thread -> m_tid = m_threads.size(); - new_thread -> m_cpu_state -> cs = m_gdt-> code_segment_selector(); + //TODO: new_thread -> m_cpu_state -> cs = m_gdt-> code_segment_selector(); // Add the thread to the array m_threads.push_back(new_thread); diff --git a/toolchain/copy_filesystem.sh b/toolchain/copy_filesystem.sh old mode 100755 new mode 100644 diff --git a/toolchain/create_disk_img.sh b/toolchain/create_disk_img.sh old mode 100755 new mode 100644 diff --git a/toolchain/make_cross_compiler.sh b/toolchain/make_cross_compiler.sh old mode 100755 new mode 100644 diff --git a/toolchain/make_documentation.sh b/toolchain/make_documentation.sh old mode 100755 new mode 100644 diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh old mode 100755 new mode 100644 diff --git a/toolchain/version.sh b/toolchain/version.sh old mode 100755 new mode 100644 From 71709b1ad85d605e25aeeea9ff3806b7127831ff Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 18 Jan 2024 15:58:30 +1300 Subject: [PATCH 03/29] 64 Bit IDT --- .../hardwarecommunication/interrupts.h | 68 ++-- kernel/include/system/cpu.h | 43 +++ kernel/include/system/gdt.h | 4 + .../src/hardwarecommunication/interrupts.cpp | 343 +++++++----------- .../hardwarecommunication/interruptstubs.s | 148 +++++--- kernel/src/kernel.cpp | 15 +- toolchain/copy_filesystem.sh | 0 toolchain/create_disk_img.sh | 0 toolchain/make_cross_compiler.sh | 0 toolchain/make_documentation.sh | 0 toolchain/run_qemu.sh | 1 + toolchain/version.sh | 0 12 files changed, 326 insertions(+), 296 deletions(-) create mode 100644 kernel/include/system/cpu.h mode change 100644 => 100755 toolchain/copy_filesystem.sh mode change 100644 => 100755 toolchain/create_disk_img.sh mode change 100644 => 100755 toolchain/make_cross_compiler.sh mode change 100644 => 100755 toolchain/make_documentation.sh mode change 100644 => 100755 toolchain/run_qemu.sh mode change 100644 => 100755 toolchain/version.sh diff --git a/kernel/include/hardwarecommunication/interrupts.h b/kernel/include/hardwarecommunication/interrupts.h index f47843be..a25dc6e7 100644 --- a/kernel/include/hardwarecommunication/interrupts.h +++ b/kernel/include/hardwarecommunication/interrupts.h @@ -11,11 +11,14 @@ #include #include #include +#include namespace MaxOS { namespace hardwarecommunication { + + class InterruptManager; /** @@ -36,24 +39,22 @@ namespace MaxOS { }; /** - * @struct GateDescriptor - * @brief Describes a gate in the Interrupt Descriptor Table + * @struct IDTR + * @brief A struct that holds the IDT register */ - struct GateDescriptor { - uint16_t handler_address_low_bits; - uint16_t gdt_code_segment_selector; - uint8_t reserved; - uint8_t access; - uint16_t handler_address_high_bits; + struct IDTR { + uint16_t limit; + uint64_t base; } __attribute__((packed)); - /** - * @struct InterruptDescriptorTablePointer - * @brief Describes the Interrupt Descriptor Table - */ - struct InterruptDescriptorTablePointer { - uint16_t size; - uint32_t base; + struct InterruptDescriptor{ + uint16_t address_low_bits; + uint16_t segment_selector; + uint8_t ist; + uint8_t flags; + uint16_t address_mid_bits; + uint32_t address_high_bits; + uint32_t reserved; } __attribute__((packed)); /** @@ -71,12 +72,15 @@ namespace MaxOS { InterruptHandler* m_interrupt_handlers[256]; system::ThreadManager* m_thread_manager; - static GateDescriptor s_interrupt_descriptor_table[256]; + static InterruptDescriptor s_interrupt_descriptor_table[256]; - static void set_interrupt_descriptor_table_entry(uint8_t interrupt, uint16_t code_segment_selector_offset, void (*handler)(), uint8_t DescriptorPrivilegeLevel, uint8_t descriptor_type); + static void set_interrupt_descriptor_table_entry(uint8_t interrupt, void (*handler)(), uint8_t descriptor_privilege_level); static void InterruptIgnore(); + // Error Codes + // TODO + //Various Interrupts static void HandleInterruptRequest0x00(); static void HandleInterruptRequest0x01(); @@ -96,7 +100,9 @@ namespace MaxOS { static void HandleInterruptRequest0x80(); static void HandleInterruptRequest0x0F(); static void HandleInterruptRequest0x31(); + static void HandleInterruptRequest0x60(); + // Exceptions static void HandleException0x00(); static void HandleException0x01(); static void HandleException0x02(); @@ -105,16 +111,16 @@ namespace MaxOS { static void HandleException0x05(); static void HandleException0x06(); static void HandleException0x07(); - static void HandleException0x08(); + static void HandleInterruptError0x08(); static void HandleException0x09(); - static void HandleException0x0A(); - static void HandleException0x0B(); - static void HandleException0x0C(); - static void HandleException0x0D(); - static void HandleException0x0E(); + static void HandleInterruptError0x0A(); + static void HandleInterruptError0x0B(); + static void HandleInterruptError0x0C(); + static void HandleInterruptError0x0D(); + static void HandleInterruptError0x0E(); static void HandleException0x0F(); static void HandleException0x10(); - static void HandleException0x11(); + static void HandleInterruptError0x11(); static void HandleException0x12(); static void HandleException0x13(); static void HandleException0x14(); @@ -130,20 +136,12 @@ namespace MaxOS { static void HandleException0x1E(); static void HandleException0x1F(); + static system::cpu_status_t* HandleInterrupt(system::cpu_status_t* status); - static uint32_t HandleInterrupt(uint8_t interrupt, uint32_t esp); - static uint32_t HandleInterruptRequest(uint32_t esp); - uint32_t handle_interrupt_request(uint8_t interrupt, uint32_t esp); - - //PIC Cominunication - Port8BitSlow pic_master_command_port; - Port8BitSlow pic_master_data_port; - Port8BitSlow pic_slave_command_port; - Port8BitSlow pic_slave_data_port; - + system::cpu_status_t* handle_interrupt_request(system::cpu_status_t*); public: - InterruptManager(uint16_t hardware_interrupt_offset, system::GlobalDescriptorTable*global_descriptor_table, system::ThreadManager* thread_manager, common::OutputStream* handler); + InterruptManager(uint16_t hardware_interrupt_offset, common::OutputStream* handler); ~InterruptManager(); uint16_t hardware_interrupt_offset(); diff --git a/kernel/include/system/cpu.h b/kernel/include/system/cpu.h new file mode 100644 index 00000000..83659bdb --- /dev/null +++ b/kernel/include/system/cpu.h @@ -0,0 +1,43 @@ +// +// Created by 98max on 17/01/2024. +// + +#ifndef MAXOS_SYSTEM_CPU_H +#define MAXOS_SYSTEM_CPU_H + +namespace MaxOS{ + + namespace system{ + + typedef struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + uint64_t interrupt_number; + uint64_t error_code; + + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; + } __attribute__((__packed__)) cpu_status_t ; + + } + +} + +#endif // MAXOS_SYSTEM_CPU_H diff --git a/kernel/include/system/gdt.h b/kernel/include/system/gdt.h index 2ea63d74..500a83a1 100644 --- a/kernel/include/system/gdt.h +++ b/kernel/include/system/gdt.h @@ -12,6 +12,10 @@ namespace MaxOS { namespace system { + /** + * @struct GDTR + * @brief A struct used to store information for the GDT Register + */ struct GDTR { uint16_t limit; uint64_t address; diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index c962ea85..3cdb4d63 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -3,6 +3,7 @@ // #include +#include using namespace MaxOS; using namespace MaxOS::common; @@ -13,7 +14,7 @@ using namespace MaxOS::system; InterruptManager* InterruptManager::s_active_interrupt_manager = 0; OutputStream* InterruptManager::s_error_messages = 0; -GateDescriptor InterruptManager::s_interrupt_descriptor_table[256]; +InterruptDescriptor InterruptManager::s_interrupt_descriptor_table[256]; ///__Handler__ @@ -43,113 +44,69 @@ void InterruptHandler::handle_interrupt() { -InterruptManager::InterruptManager(uint16_t hardware_interrupt_offset, system::GlobalDescriptorTable*global_descriptor_table,ThreadManager*thread_manager, OutputStream* handler) +InterruptManager::InterruptManager(uint16_t hardware_interrupt_offset, OutputStream* handler) : common::InputStream(handler), - m_hardware_interrupt_offset(hardware_interrupt_offset), - m_thread_manager(thread_manager), - pic_master_command_port(0x20), - pic_master_data_port(0x21), - pic_slave_command_port(0xA0), - pic_slave_data_port(0xA1) + m_hardware_interrupt_offset(hardware_interrupt_offset) { - // TODO: Re write the IDT - return; - uint32_t code_segment = 0; - - // By default ignore all interrupts so any un handled interrupts wont cause a fault - const uint8_t IDT_INTERRUPT_GATE = 0xE; - for(uint8_t i = 255; i > 0; --i) - { - set_interrupt_descriptor_table_entry(i, code_segment, &InterruptIgnore, 0, IDT_INTERRUPT_GATE); - m_interrupt_handlers[i] = 0; - } - - // First is also clear - set_interrupt_descriptor_table_entry(0, code_segment, &InterruptIgnore, 0,IDT_INTERRUPT_GATE); - m_interrupt_handlers[0] = 0; - - - - //Set Up the base interrupts - set_interrupt_descriptor_table_entry(0x00, code_segment, &HandleException0x00, 0, IDT_INTERRUPT_GATE); //Division by zero - set_interrupt_descriptor_table_entry(0x01, code_segment, &HandleException0x01, 0, IDT_INTERRUPT_GATE); //Single-step interrupt (see trap flag) - set_interrupt_descriptor_table_entry(0x02, code_segment, &HandleException0x02, 0, IDT_INTERRUPT_GATE); //NMI - set_interrupt_descriptor_table_entry(0x03, code_segment, &HandleException0x03, 0, IDT_INTERRUPT_GATE); //Breakpoint (which benefits from the shorter 0xCC encoding of INT 3) - set_interrupt_descriptor_table_entry(0x04, code_segment, &HandleException0x04, 0, IDT_INTERRUPT_GATE); //Overflow - set_interrupt_descriptor_table_entry(0x05, code_segment, &HandleException0x05, 0, IDT_INTERRUPT_GATE); //Bound Range Exceeded - set_interrupt_descriptor_table_entry(0x06, code_segment, &HandleException0x06, 0, IDT_INTERRUPT_GATE); //Invalid Opcode - set_interrupt_descriptor_table_entry(0x07, code_segment, &HandleException0x07, 0, IDT_INTERRUPT_GATE); //Coprocessor not available - set_interrupt_descriptor_table_entry(0x08, code_segment, &HandleException0x08, 0, IDT_INTERRUPT_GATE); //Double Fault - set_interrupt_descriptor_table_entry(0x09, code_segment, &HandleException0x09, 0, IDT_INTERRUPT_GATE); //Coprocessor Segment Overrun (386 or earlier only) - set_interrupt_descriptor_table_entry(0x0A, code_segment, &HandleException0x0A, 0, IDT_INTERRUPT_GATE); //Invalid Task State Segment - set_interrupt_descriptor_table_entry(0x0B, code_segment, &HandleException0x0B, 0, IDT_INTERRUPT_GATE); //Segment not present - set_interrupt_descriptor_table_entry(0x0C, code_segment, &HandleException0x0C, 0, IDT_INTERRUPT_GATE); //Stack Segment Fault - set_interrupt_descriptor_table_entry(0x0D, code_segment, &HandleException0x0D, 0, IDT_INTERRUPT_GATE); //General Protection Fault - set_interrupt_descriptor_table_entry(0x0E, code_segment, &HandleException0x0E, 0, IDT_INTERRUPT_GATE); //Page Fault - set_interrupt_descriptor_table_entry(0x0F, code_segment, &HandleException0x0F, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x10, code_segment, &HandleException0x10, 0, IDT_INTERRUPT_GATE); //x87 Floating Point Exception - set_interrupt_descriptor_table_entry(0x11, code_segment, &HandleException0x11, 0, IDT_INTERRUPT_GATE); //Alignment Check - set_interrupt_descriptor_table_entry(0x12, code_segment, &HandleException0x12, 0, IDT_INTERRUPT_GATE); //Machine Check - set_interrupt_descriptor_table_entry(0x13, code_segment, &HandleException0x13, 0, IDT_INTERRUPT_GATE); //SIMD Floating-Point Exception - set_interrupt_descriptor_table_entry(0x14, code_segment, &HandleException0x14, 0, IDT_INTERRUPT_GATE); //Virtualization Exception - set_interrupt_descriptor_table_entry(0x15, code_segment, &HandleException0x15, 0, IDT_INTERRUPT_GATE); //Control Protection Exception - set_interrupt_descriptor_table_entry(0x16, code_segment, &HandleException0x16, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x17, code_segment, &HandleException0x17, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x18, code_segment, &HandleException0x18, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x19, code_segment, &HandleException0x19, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1A, code_segment, &HandleException0x1A, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1B, code_segment, &HandleException0x1B, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1C, code_segment, &HandleException0x1C, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1D, code_segment, &HandleException0x1D, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1E, code_segment, &HandleException0x1E, 0, IDT_INTERRUPT_GATE); //reserved - set_interrupt_descriptor_table_entry(0x1F, code_segment, &HandleException0x1F, 0, IDT_INTERRUPT_GATE); //reserved - - - //Set up the hardware interrupts (offset by 0x20) //Ranges 0x20 - 0x30 - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x00, code_segment, &HandleInterruptRequest0x00, 0, IDT_INTERRUPT_GATE); //0x20 - Default PIC interval / Timer - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x01, code_segment, &HandleInterruptRequest0x01, 0, IDT_INTERRUPT_GATE); //0x21 - Keyboard - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x02, code_segment, &HandleInterruptRequest0x02, 0, IDT_INTERRUPT_GATE); //0x22 - Cascade (used internally by the two PICs. never raised) - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x03, code_segment, &HandleInterruptRequest0x03, 0, IDT_INTERRUPT_GATE); //0x23 - COM2, COM4 - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x04, code_segment, &HandleInterruptRequest0x04, 0, IDT_INTERRUPT_GATE); //0x24 - COM1, COM3 - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x05, code_segment, &HandleInterruptRequest0x05, 0, IDT_INTERRUPT_GATE); //0x25 - LPT2, LPT4 - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x06, code_segment, &HandleInterruptRequest0x06, 0, IDT_INTERRUPT_GATE); //0x26 - LPT1 - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x07, code_segment, &HandleInterruptRequest0x07, 0, IDT_INTERRUPT_GATE); //0x27 - Floppy Disk - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x08, code_segment, &HandleInterruptRequest0x08, 0, IDT_INTERRUPT_GATE); //0x28 - CMOS Real Time Clock - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x09, code_segment, &HandleInterruptRequest0x09, 0, IDT_INTERRUPT_GATE); //0x29 - Free for peripherals / legacy SCSI / NIC - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0A, code_segment, &HandleInterruptRequest0x0A, 0, IDT_INTERRUPT_GATE); //0x2A - Free for peripherals / SCSI / NIC - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0B, code_segment, &HandleInterruptRequest0x0B, 0, IDT_INTERRUPT_GATE); //0x2B - Free for peripherals / SCSI / NIC - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0C, code_segment, &HandleInterruptRequest0x0C, 0, IDT_INTERRUPT_GATE); //0x0C - Mouse - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0D, code_segment, &HandleInterruptRequest0x0D, 0, IDT_INTERRUPT_GATE); //0x2D - FPU / Coprocessor / Inter-processor - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0E, code_segment, &HandleInterruptRequest0x0E, 0, IDT_INTERRUPT_GATE); //0x2E - Primary ATA Hard Disk - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0F, code_segment, &HandleInterruptRequest0x0F, 0, IDT_INTERRUPT_GATE); //0x2F - Secondary ATA Hard Disk - set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x60, code_segment, &HandleInterruptRequest0x80, 0, IDT_INTERRUPT_GATE); //0x80 - Sys calls - - //Send Initialization Control Words - pic_master_command_port.write(0x11); - pic_slave_command_port.write(0x11); - - // Remap the PIC to use the hardware interrupt offset - pic_master_data_port.write(hardware_interrupt_offset); - pic_slave_data_port.write(hardware_interrupt_offset + 8); - - //Tell PICs their roles - pic_master_data_port.write(0x04); //Master - pic_slave_data_port.write(0x02); //Slave - - //Tell PICS that they are in 8086 mode - pic_master_data_port.write(0x01); - pic_slave_data_port.write(0x01); - - // Clear the interrupt mask to enable all interrupts - pic_master_data_port.write(0x00); - pic_slave_data_port.write(0x00); + // Full the table of interrupts with 0 + for(uint16_t i = 0; i < 256; i++) { + s_interrupt_descriptor_table[i].address_low_bits = 0; + s_interrupt_descriptor_table[i].address_mid_bits = 0; + s_interrupt_descriptor_table[i].address_high_bits = 0; + s_interrupt_descriptor_table[i].segment_selector = 0; + s_interrupt_descriptor_table[i].ist = 0; + s_interrupt_descriptor_table[i].flags = 0; + } + + //Set Up the base interrupts + set_interrupt_descriptor_table_entry(0x00, &HandleException0x00, 0); // Division by zero + set_interrupt_descriptor_table_entry(0x01, &HandleException0x01, 0); // Debug + set_interrupt_descriptor_table_entry(0x02, &HandleException0x02, 0); // Non-maskable interrupt + set_interrupt_descriptor_table_entry(0x03, &HandleException0x03, 0); // Breakpoint + set_interrupt_descriptor_table_entry(0x04, &HandleException0x04, 0); // Overflow + set_interrupt_descriptor_table_entry(0x05, &HandleException0x05, 0); // Bound Range Exceeded + set_interrupt_descriptor_table_entry(0x06, &HandleException0x06, 0); // Invalid Opcode + set_interrupt_descriptor_table_entry(0x06, &HandleException0x07, 0); // Device Not Available + set_interrupt_descriptor_table_entry(0x08, &HandleInterruptError0x08, 0); // Double Fault + set_interrupt_descriptor_table_entry(0x09, &HandleException0x09, 0); // Coprocessor Segment Overrun + set_interrupt_descriptor_table_entry(0x0A, &HandleInterruptError0x0A, 0); // Invalid TSS + set_interrupt_descriptor_table_entry(0x0B, &HandleInterruptError0x0B, 0); // Segment Not Present + set_interrupt_descriptor_table_entry(0x0C, &HandleInterruptError0x0C, 0); // Stack-Segment Fault + set_interrupt_descriptor_table_entry(0x0D, &HandleInterruptError0x0D, 0); // General Protection Fault + set_interrupt_descriptor_table_entry(0x0E, &HandleInterruptError0x0E, 0); // Page Fault + set_interrupt_descriptor_table_entry(0x0F, &HandleException0x0F, 0); // Reserved + set_interrupt_descriptor_table_entry(0x10, &HandleException0x10, 0); // x87 Floating-Point Exception + set_interrupt_descriptor_table_entry(0x11, &HandleInterruptError0x11, 0); // Alignment Check + set_interrupt_descriptor_table_entry(0x12, &HandleException0x12, 0); // Machine Check + set_interrupt_descriptor_table_entry(0x13, &HandleException0x13, 0); // SIMD Floating-Point Exception + set_interrupt_descriptor_table_entry(0x14, &HandleException0x14, 0); // Reserved: Virtualization Exception + set_interrupt_descriptor_table_entry(0x15, &HandleException0x15, 0); // Reserved + set_interrupt_descriptor_table_entry(0x16, &HandleException0x16, 0); // Reserved + set_interrupt_descriptor_table_entry(0x17, &HandleException0x17, 0); // Reserved + set_interrupt_descriptor_table_entry(0x18, &HandleException0x18, 0); // Reserved + set_interrupt_descriptor_table_entry(0x19, &HandleException0x19, 0); // Reserved + set_interrupt_descriptor_table_entry(0x1A, &HandleException0x1A, 0); // Reserved + set_interrupt_descriptor_table_entry(0x1B, &HandleException0x1B, 0); // Reserved + set_interrupt_descriptor_table_entry(0x1C, &HandleException0x1C, 0); // Reserved + set_interrupt_descriptor_table_entry(0x1D, &HandleException0x1D, 0); // Reserved + set_interrupt_descriptor_table_entry(0x1E, &HandleException0x1E, 0); // Security Exception + set_interrupt_descriptor_table_entry(0x1F, &HandleException0x1F, 0); // Reserved + + // Set up the hardware interrupts + set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x00, &HandleInterruptRequest0x00, 0); // Advanced Programmable Interrupt Controller (APIC) Timer Interrupt + set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x01, &HandleInterruptRequest0x01, 0); // Keyboard Interrupt + set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x02, &HandleInterruptRequest0x02, 0); // Cascade (used internally by the two PICs. never raised) + set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x0C, &HandleInterruptRequest0x0C, 0); // Mouse Interrupt + + // Set up the system call interrupt + set_interrupt_descriptor_table_entry(hardware_interrupt_offset + 0x60, &HandleInterruptRequest0x60, 0); // System Call Interrupt //Tell the processor to use the IDT - InterruptDescriptorTablePointer idt_pointer; - idt_pointer.size = 256*sizeof(GateDescriptor) - 1; - idt_pointer.base = (uint32_t)s_interrupt_descriptor_table; - asm volatile("lidt %0" : : "m" (idt_pointer)); + IDTR idt; + idt.limit = 256 * sizeof(InterruptDescriptor) - 1; + idt.base = (uint64_t)s_interrupt_descriptor_table; + asm volatile("lidt %0" : : "m" (idt)); }; InterruptManager::~InterruptManager() @@ -164,20 +121,29 @@ InterruptManager::~InterruptManager() * @param interrupt Interrupt number * @param code_segment_selector_offset Code segment * @param handler Interrupt Handler - * @param DescriptorPrivilegeLevel Descriptor Privilege Level + * @param descriptor_privilege_level Descriptor Privilege Level * @param descriptor_type Descriptor Type */ -void InterruptManager::set_interrupt_descriptor_table_entry(uint8_t interrupt, uint16_t code_segment_selector_offset, void (*handler)(), uint8_t DescriptorPrivilegeLevel, uint8_t descriptor_type) +void InterruptManager::set_interrupt_descriptor_table_entry(uint8_t interrupt, void (*handler)(), uint8_t descriptor_privilege_level) { - // Store the handler function in the IDT - s_interrupt_descriptor_table[interrupt].handler_address_low_bits = ((uint32_t) handler) & 0xFFFF; - s_interrupt_descriptor_table[interrupt].handler_address_high_bits = (((uint32_t) handler) >> 16) & 0xFFFF; - s_interrupt_descriptor_table[interrupt].gdt_code_segment_selector = code_segment_selector_offset; - - // Set the access - const uint8_t IDT_DESC_PRESENT = 0x80; - s_interrupt_descriptor_table[interrupt].access = IDT_DESC_PRESENT | ((DescriptorPrivilegeLevel & 3) << 5) | descriptor_type; - s_interrupt_descriptor_table[interrupt].reserved = 0; + + // Get the address of the handler and the entry in the IDT + uint64_t handler_address = (uint64_t)handler; + InterruptDescriptor* interrupt_descriptor = &s_interrupt_descriptor_table[interrupt]; + + // Set the handler address + interrupt_descriptor->address_low_bits = handler_address & 0xFFFF; + interrupt_descriptor->address_mid_bits = (handler_address >> 16) & 0xFFFF; + interrupt_descriptor->address_high_bits = (handler_address >> 32) & 0xFFFFFFFF; + + // Set the kernel code segment offset + interrupt_descriptor->segment_selector = 0x08; + + // Disable IST + interrupt_descriptor->ist = 0; + + // Set the flags (Trap Gate, Present and the Descriptor Privilege Level) + interrupt_descriptor->flags = 0b1110 | ((descriptor_privilege_level & 0b11) << 5) | (1 << 7); } @@ -193,7 +159,6 @@ void InterruptManager::activate() { // Set the current interrupt manager and start interrupts s_active_interrupt_manager = this; asm("sti"); - } /** @@ -212,98 +177,17 @@ void InterruptManager::deactivate() /** * @brief Handles the interrupt request by passing it to the interrupt manager * - * @param interruptNumber The interrupt number - * @param esp The stack pointer - * @return The stack pointer - */ -uint32_t InterruptManager::HandleInterrupt(uint8_t interrupt, uint32_t esp) -{ - - // If there is an active interrupt manager, handle the interrupt - if(s_active_interrupt_manager != 0) - return s_active_interrupt_manager->handle_interrupt_request(interrupt, esp); - - // CPU can continue - return esp; -} - -/** - * @brief Handles the interrupt request and runs the interrupt handler if there is one - * - * @param interruptNumber The interrupt number - * @param esp The stack pointer + * @param status The current stack pointer * @return The stack pointer */ -uint32_t InterruptManager::handle_interrupt_request(uint8_t interrupt, uint32_t esp) -{ - - // If there is an interrupt handler, run it - if(m_interrupt_handlers[interrupt] != 0){ - m_interrupt_handlers[interrupt]->handle_interrupt(); - } - else if(interrupt != 0x20){ - - switch (interrupt) { - - case 0x00: s_error_messages->write("[ERROR] Divide by zero (int 0x00)"); break; - case 0x01: s_error_messages->write("[ERROR] Single-step interrupt (int 0x01)"); break; - case 0x02: s_error_messages->write("[ERROR] Non maskable interrupt (int 0x02)"); break; - case 0x03: s_error_messages->write("[ERROR] Breakpoint (int 0x03)"); break; - case 0x04: s_error_messages->write("[ERROR] Overflow (int 0x04)"); break; - case 0x05: s_error_messages->write("[ERROR] Bounds check (int 0x05)"); break; - case 0x06: s_error_messages->write("[ERROR] Invalid opcode (int 0x06)"); break; - case 0x07: s_error_messages->write("[ERROR] Coprocessor not available (int 0x07)"); break; - case 0x08: s_error_messages->write("[ERROR] Double fault (int 0x08)"); break; - case 0x09: s_error_messages->write("[ERROR] Coprocessor segment overrun (int 0x09)"); break; - case 0x0A: s_error_messages->write("[ERROR] Invalid TSS (int 0x0A)"); break; - case 0x0B: s_error_messages->write("[ERROR] Segment not present (int 0x0B)"); break; - case 0x0C: s_error_messages->write("[ERROR] Stack segment fault (int 0x0C)"); break; - case 0x0D: s_error_messages->write("[ERROR] General protection fault (int 0x0D)"); break; - case 0x0E: s_error_messages->write("[ERROR] Page fault (int 0x0E)"); break; - case 0x0F: s_error_messages->write("[INFO] Reserved (int 0x0F)"); break; - case 0x10: s_error_messages->write("[ERROR] x87 FPU floating point error (int 0x10)"); break; - case 0x11: s_error_messages->write("[INFO] Alignment check (int 0x11)"); break; - case 0x12: s_error_messages->write("[INFO] Machine check (int 0x12)"); break; - case 0x13: s_error_messages->write("[ERROR] SIMD floating point exception (int 0x13)"); break; - case 0x14: s_error_messages->write("[ERROR] Virtualization exception (int 0x14)"); break; - case 0x15: s_error_messages->write("[INFO] Reserved (int 0x15)"); break; - case 0x16: s_error_messages->write("[INFO] Reserved (int 0x16)"); break; - case 0x17: s_error_messages->write("[INFO] Reserved (int 0x17)"); break; - case 0x18: s_error_messages->write("[INFO] Reserved (int 0x18)"); break; - case 0x19: s_error_messages->write("[INFO] Reserved (int 0x19)"); break; - case 0x1A: s_error_messages->write("[INFO] Reserved (int 0x1A)"); break; - case 0x1B: s_error_messages->write("[INFO] Reserved (int 0x1B)"); break; - case 0x1C: s_error_messages->write("[INFO] Reserved (int 0x1C)"); break; - case 0x1D: s_error_messages->write("[INFO] Reserved (int 0x1D)"); break; - case 0x1E: s_error_messages->write("[INFO] Reserved (int 0x1E)"); break; - case 0x1F: s_error_messages->write("[INFO] Reserved (int 0x1F)"); break; - - default: - s_error_messages->write("UNHANDLED INTERRUPT 0x"); - s_error_messages->write_hex(interrupt); - s_error_messages->write(" "); - break; - - } - } +system::cpu_status_t* InterruptManager::HandleInterrupt(system::cpu_status_t *status) { - //Timer interrupt for m_tasks - if(interrupt == m_hardware_interrupt_offset) - { - esp = (uint32_t)m_thread_manager->schedule((CPUState*)esp); - } - - // Acknowledge the interrupt (if it is a hardware interrupt) - if(m_hardware_interrupt_offset <= interrupt && interrupt < m_hardware_interrupt_offset +16) - { - pic_master_command_port.write(0x20); - - // Answer the slave PIC if it was the one that sent the interrupt - if(0x28 <= interrupt) - pic_slave_command_port.write(0x20); - } + // If there is an interrupt manager handle interrupt + if(s_active_interrupt_manager != 0) + return s_active_interrupt_manager->handle_interrupt_request(status); - return esp; + // CPU Can continue + return status; } /** @@ -332,4 +216,57 @@ void InterruptManager::set_interrupt_handler(uint8_t interrupt, InterruptHandler */ void InterruptManager::remove_interrupt_handler(uint8_t interrupt) { m_interrupt_handlers[interrupt] = 0; +} + +static const char* exceptions[] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "SIMD Floating Point Exception", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "Security Exception", + "RESERVED" +}; + +cpu_status_t* InterruptManager::handle_interrupt_request(cpu_status_t* status) { + + _kprintf("Interrupt: 0x%x\n", status->interrupt_number); + + // If there is an interrupt manager, handle the interrupt + if(m_interrupt_handlers[status -> interrupt_number] != 0) + m_interrupt_handlers[status -> interrupt_number]->handle_interrupt(); + + else if(status->interrupt_number < m_hardware_interrupt_offset) + _kprintf("Exception: %s\n", exceptions[status->interrupt_number]); + + else + _kprintf("Unhandled Interrupt: 0x%x\n", status->interrupt_number); + + // Return the status + return status; } \ No newline at end of file diff --git a/kernel/src/hardwarecommunication/interruptstubs.s b/kernel/src/hardwarecommunication/interruptstubs.s index 5239c6fe..ec290c03 100644 --- a/kernel/src/hardwarecommunication/interruptstubs.s +++ b/kernel/src/hardwarecommunication/interruptstubs.s @@ -1,25 +1,90 @@ -section .data - IRQ_BASE equ 0x20 - interruptnumber db 0 +; Credit https://github.com/dreamos82/Dreamos64 -section .text - extern _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEhj +[bits 64] +[extern _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEPNS_6system12cpu_status_tE] - %macro HandleException 1 - global _ZN5MaxOS21hardwarecommunication16InterruptManager19HandleException%1Ev - _ZN5MaxOS21hardwarecommunication16InterruptManager19HandleException%1Ev: - mov byte [interruptnumber], %1 - jmp int_bottom - %endmacro +%macro HandleException 1 +[global _ZN5MaxOS21hardwarecommunication16InterruptManager19HandleException%1Ev] +_ZN5MaxOS21hardwarecommunication16InterruptManager19HandleException%1Ev: + ; When this macro is called the status registers are already on the stack + push 0 ; since we have no error code, to keep things consistent we push a default EC of 0 + push %1 ; pushing the interrupt number for easier identification by the handler + save_context ; Now we can save the general purpose registers + mov rdi, rsp ; Let's set the current stack pointer as a parameter of the interrupts_handler + cld ; Clear the direction flag + call _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEPNS_6system12cpu_status_tE ; Now we call the interrupt handler + mov rsp, rax ; use the returned context + restore_context ; We served the interrupt let's restore the previous context + add rsp, 16 ; We can discard the interrupt number and the error code + iretq ; Now we can return from the interrupt +%endmacro - %macro HandleInterruptRequest 1 - global _ZN5MaxOS21hardwarecommunication16InterruptManager26HandleInterruptRequest%1Ev - _ZN5MaxOS21hardwarecommunication16InterruptManager26HandleInterruptRequest%1Ev: - mov byte [interruptnumber], %1 + IRQ_BASE - push 0 - jmp int_bottom - %endmacro +%macro HandleInterruptRequest 1 +[global _ZN5MaxOS21hardwarecommunication16InterruptManager26HandleInterruptRequest%1Ev] +_ZN5MaxOS21hardwarecommunication16InterruptManager26HandleInterruptRequest%1Ev: + ; When this macro is called the status registers are already on the stack + push 0 ; since we have no error code, to keep things consistent we push a default EC of 0 + push (%1 + 0x20) ; pushing the interrupt number for easier identification by the handler + save_context ; Now we can save the general purpose registers + mov rdi, rsp ; Let's set the current stack pointer as a parameter of the interrupts_handler + cld ; Clear the direction flag + call _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEPNS_6system12cpu_status_tE ; Now we call the interrupt handler + mov rsp, rax ; use the returned context + restore_context ; We served the interrupt let's restore the previous context + add rsp, 16 ; We can discard the interrupt number and the error code + iretq ; Now we can return from the interrupt +%endmacro +%macro HandleInterruptError 1 +[global _ZN5MaxOS21hardwarecommunication16InterruptManager24HandleInterruptError%1Ev] +_ZN5MaxOS21hardwarecommunication16InterruptManager24HandleInterruptError%1Ev: + push %1 ; In this case the error code is already present on the stack + save_context + mov rdi, rsp + cld + call _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEPNS_6system12cpu_status_tE + restore_context + add rsp, 16 + iretq +%endmacro + +%macro save_context 0 + push rax + push rbx + push rcx + push rdx + push rbp + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 +%endmacro + +%macro restore_context 0 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rbp + pop rdx + pop rcx + pop rbx + pop rax +%endmacro + +; Exception handlers HandleException 0x00 HandleException 0x01 HandleException 0x02 @@ -28,16 +93,16 @@ HandleException 0x04 HandleException 0x05 HandleException 0x06 HandleException 0x07 -HandleException 0x08 +HandleInterruptError 0x08 HandleException 0x09 -HandleException 0x0A -HandleException 0x0B -HandleException 0x0C -HandleException 0x0D -HandleException 0x0E +HandleInterruptError 0x0A +HandleInterruptError 0x0B +HandleInterruptError 0x0C +HandleInterruptError 0x0D +HandleInterruptError 0x0E HandleException 0x0F HandleException 0x10 -HandleException 0x11 +HandleInterruptError 0x11 HandleException 0x12 HandleException 0x13 HandleException 0x14 @@ -53,6 +118,7 @@ HandleException 0x1D HandleException 0x1E HandleException 0x1F +; Hardware interrupt handlers HandleInterruptRequest 0x00 HandleInterruptRequest 0x01 HandleInterruptRequest 0x02 @@ -70,34 +136,4 @@ HandleInterruptRequest 0x0D HandleInterruptRequest 0x0E HandleInterruptRequest 0x0F HandleInterruptRequest 0x31 -HandleInterruptRequest 0x80 - -int_bottom: - push bp - push di - push si - - push dx - push cx - push bx - push ax - - push sp - push interruptnumber - call _ZN5MaxOS21hardwarecommunication16InterruptManager15HandleInterruptEhj - mov ax, sp - - pop ax - pop bx - pop cx - pop dx - - pop si - pop di - pop bp - - add sp, 4 - -global _ZN5MaxOS21hardwarecommunication16InterruptManager15InterruptIgnoreEv -_ZN5MaxOS21hardwarecommunication16InterruptManager15InterruptIgnoreEv: - iret +HandleInterruptRequest 0x60 \ No newline at end of file diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 1fbdac12..bb3aa795 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -114,8 +114,19 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) GlobalDescriptorTable gdt; _kprintf("GDT set up\n"); + InterruptManager interrupts(0x20, 0); + _kprintf("IDT set up\n"); + + interrupts.activate(); + _kprintf("IDT activated\n"); + + asm("int $0x80"); + _kprintf("IDT test completed\n"); + // TODO: 64 bit architecture rewrite - return; + while (true) { + asm("hlt"); //TODO: This causes a Double Fault and then infinte General Protection Faults + } // Make the multiboot header Multiboot multiboot(addr); @@ -172,7 +183,7 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) cout << "-- Set Up Thread Management\n"; systemSetupHeaderStream << "."; - InterruptManager interrupts(0x20, &gdt, &threadManager, &cout); //Instantiate the function + //TODO: InterruptManager interrupts(0x20, &gdt, &threadManager, &cout); //Instantiate the function cout << "-- Set Up Interrupts\n"; systemSetupHeaderStream << "."; diff --git a/toolchain/copy_filesystem.sh b/toolchain/copy_filesystem.sh old mode 100644 new mode 100755 diff --git a/toolchain/create_disk_img.sh b/toolchain/create_disk_img.sh old mode 100644 new mode 100755 diff --git a/toolchain/make_cross_compiler.sh b/toolchain/make_cross_compiler.sh old mode 100644 new mode 100755 diff --git a/toolchain/make_documentation.sh b/toolchain/make_documentation.sh old mode 100644 new mode 100755 diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh old mode 100644 new mode 100755 index 89d6e840..f8a2c09f --- a/toolchain/run_qemu.sh +++ b/toolchain/run_qemu.sh @@ -139,6 +139,7 @@ QEMU_ARGS="$QEMU_ARGS -net nic,model=$NETWORK_DEVICE" # Add a network devi QEMU_ARGS="$QEMU_ARGS $PORT_FORWARDING" # Add port forwarding QEMU_ARGS="$QEMU_ARGS -drive file=$IMAGE_PATH,format=raw" # Add the image as a drive QEMU_ARGS="$QEMU_ARGS,if=ide,cache=directsync,id=disk0" # Configure the drive to be an ide drive with direct sync caching +QEMU_ARGS="$QEMU_ARGS -no-reboot -no-shutdown" # Don't reboot or shutdown on exit # Run qemu msg "Running qemu with args: $QEMU_ARGS" diff --git a/toolchain/version.sh b/toolchain/version.sh old mode 100644 new mode 100755 From bf1ee5540de903d4953158b623d78bd6ff9c43b0 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 18 Jan 2024 16:06:31 +1300 Subject: [PATCH 04/29] Update Contributing Docs --- docs/CONTRIBUTING.md | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 26bb716d..2ba0aea1 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -11,27 +11,27 @@ We love your input! We want to make contributing to this project as easy and tra We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. ## Code Standard -To keep the code understanble please make sure it is formatted and reable. Additionally add comments exapling what your function does and the various steps. Summary's and params are only needed if the function is intended to be used on a wider scale e.g. printf but not EtherFrameProvider::OnRawDataReceived(...); +To keep the code understanble please make sure it is formatted and reable. Please look in the coding style [docs](Styles/Coding%20Style.md) for more information. ## We Use [GitHub Flow](https://guides.github.com/introduction/flow/index.html), So All Code Changes Happen Through Pull Requests Pull requests are the best way to propose changes to the codebase (we use [GitHub Flow](https://guides.github.com/introduction/flow/index.html)). We actively welcome your pull requests: -1. Fork the repo and create your branch from `m_is_master`. +1. Fork the repo and create your branch from `master`. 2. If you've added code that should be tested, add tests. 3. If you've changed APIs, update the documentation. -4. Ensure the test suite passes. -5. Make sure your code lints. +4. Clean up the code: clear any debug code, make sure no warnings are generated when compiling, etc. +5. Ensure the kernel builds and runs. 6. Issue that pull request! ## Report bugs using GitHub's [issues](https://github.com/briandk/transcriptase-atom/issues) -We use GitHub issues to track public bugs. Report a bug by [opening a new issue](); it's that easy! +We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/maxtyson123/MaxOS/issues/new/choose); it's that easy! -## write bug reports with detail, m_background, and sample code -[This is an example](http://stackoverflow.com/q/12488905/180626) of a bug report someone wrote, and I think it's not a bad model. Here's [another example from Craig Hockenberry](http://www.openradar.me/11905408), an app developer whom I greatly respect. +## Write bug reports with detail, background, and sample code +[This is an example](http://stackoverflow.com/q/12488905/180626) of a bug report someone wrote on stack overflow. **Great Bug Reports** tend to have: -- A quick summary and/or m_background +- A quick summary and/or background - Steps to reproduce - Be specific! - Give sample code if you can. [This stackoverflow question](http://stackoverflow.com/q/12488905/180626) includes sample code that *anyone* with a base R setup can run to reproduce what I was seeing @@ -39,16 +39,7 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue] - What actually happens - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) -People *love* thorough bug reports. I'm not even kidding. - -## Use a Consistent Coding Style -I'm again borrowing these from [Facebook's Guidelines](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) - -* 2 spaces for indentation rather than tabs - +People *love* thorough bug reports. ## License -By contributing, you agree that your contributions will be licensed under its MIT License. - -## References -This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) +By contributing, you agree that your contributions will be licensed under this projects [LICENSE](../LICENSE). From cd30a185915e0e3873ad06eab31d5b2f2943e447 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 18 Jan 2024 17:44:15 +1300 Subject: [PATCH 05/29] ACPI --- kernel/include/common/string.h | 13 +++- kernel/include/hardwarecommunication/acpi.h | 74 +++++++++++++++++++ kernel/include/system/multiboot.h | 5 ++ kernel/src/common/string.cpp | 82 ++++++++++++++++++++- kernel/src/hardwarecommunication/acpi.cpp | 81 ++++++++++++++++++++ kernel/src/kernel.cpp | 12 +-- kernel/src/system/multiboot.cpp | 13 ++++ 7 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 kernel/include/hardwarecommunication/acpi.h create mode 100644 kernel/src/hardwarecommunication/acpi.cpp diff --git a/kernel/include/common/string.h b/kernel/include/common/string.h index dd82e4a1..4341b821 100644 --- a/kernel/include/common/string.h +++ b/kernel/include/common/string.h @@ -49,7 +49,18 @@ namespace MaxOS { }; typedef String string; - } +// Compare functions +bool strcmp(char const *str1, char const *str2); +bool strcmp(char const *str1, MaxOS::String const &str2); +bool strcmp(MaxOS::String const &str1, char const *str2); +bool strcmp(MaxOS::String const &str1, MaxOS::String const &str2); + +// Compare limited functions +bool strncmp(char const *str1, char const *str2, int length); +bool strncmp(char const *str1, MaxOS::String const &str2, int length); +bool strncmp(MaxOS::String const &str1, char const *str2, int length); +bool strncmp(MaxOS::String const &str1, MaxOS::String const &str2, int length); + #endif //MAXOS_STRING_H diff --git a/kernel/include/hardwarecommunication/acpi.h b/kernel/include/hardwarecommunication/acpi.h new file mode 100644 index 00000000..d997ed8d --- /dev/null +++ b/kernel/include/hardwarecommunication/acpi.h @@ -0,0 +1,74 @@ +// +// Created by 98max on 18/01/2024. +// + +#ifndef MAXOS_HARDWARECOMMUNICATION_ACPI_H +#define MAXOS_HARDWARECOMMUNICATION_ACPI_H + +#include +#include +#include +#include + +namespace MaxOS { + namespace hardwarecommunication { + + struct RSDPDescriptor { + char signature[8]; + uint8_t checksum; + char OEMID[6]; + uint8_t revision; + uint32_t rsdt_address; + } __attribute__ ((packed)); + + struct RSDPDescriptor2 { + RSDPDescriptor firstPart; + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint8_t reserved[3]; + } __attribute__ ((packed)); + + struct ACPISDTHeader { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char OEM_id[6]; + char OEM_table_id[8]; + uint32_t OEM_revision; + uint32_t creator_id; + uint32_t creator_revision; + } __attribute__ ((packed)); + + struct RSDT { + ACPISDTHeader header; + uint32_t pointers[]; + }; + + struct XSDT { + ACPISDTHeader header; + uint64_t pointers[]; + }; + + class AdvancedConfigurationAndPowerInterface { + protected: + uint8_t m_type; + ACPISDTHeader* m_header; + + XSDT* m_xsdt; + RSDT* m_rsdt; + + bool validate(char* discriptor, size_t length); + + public: + AdvancedConfigurationAndPowerInterface(system::Multiboot* multiboot); + ~AdvancedConfigurationAndPowerInterface(); + + ACPISDTHeader* find(const char* signature); + }; + + } +} + +#endif // MAXOS_HARDWARECOMMUNICATION_ACPI_H diff --git a/kernel/include/system/multiboot.h b/kernel/include/system/multiboot.h index debc3b36..a19c54a7 100644 --- a/kernel/include/system/multiboot.h +++ b/kernel/include/system/multiboot.h @@ -423,6 +423,8 @@ namespace MaxOS { multiboot_tag_basic_meminfo* m_basic_meminfo; multiboot_tag_string* m_bootloader_name; multiboot_tag_mmap* m_mmap; + multiboot_tag_old_acpi* m_old_acpi; + multiboot_tag_new_acpi* m_new_acpi; public: Multiboot(unsigned long addr); @@ -432,6 +434,9 @@ namespace MaxOS { multiboot_tag_basic_meminfo* get_basic_meminfo(); multiboot_tag_string* get_bootloader_name(); multiboot_tag_mmap* get_mmap(); + multiboot_tag_old_acpi* get_old_acpi(); + multiboot_tag_new_acpi* get_new_acpi(); + }; } } diff --git a/kernel/src/common/string.cpp b/kernel/src/common/string.cpp index 59637ee7..96785917 100644 --- a/kernel/src/common/string.cpp +++ b/kernel/src/common/string.cpp @@ -344,4 +344,84 @@ char& String::operator[](int index) { */ char& String::operator[](int index) const { return m_string[index]; -} \ No newline at end of file +} + + +/** + * @brief Checks if one string is equal to another + * + * @param str1 The first string + * @param str2 The second string + * @return True if the strings are equal, false otherwise + */ +bool strcmp(char const *str1, char const *str2) { + + // Check if the strings are equal + for (int i = 0; str1[i] != '\0' || str2[i] != '\0'; i++) + if (str1[i] != str2[i]) + return false; + + // The strings are equal + return true; + +} + +bool strcmp(char const *str1, String const &str2) { + + // Use the other strcmp function + return strcmp(str1, str2.c_str()); + +} + +bool strcmp(String const &str1, char const *str2) { + + // Use the other strcmp function + return strcmp(str1.c_str(), str2); +} + +bool strcmp(String const &str1, String const &str2) { + + // Use the other strcmp function + return strcmp(str1.c_str(), str2.c_str()); + +} + +/** + * @brief Checks if one string is equal to another + * + * @param str1 The first string + * @param str2 The second string + * @param length The length of the strings + * @return True if the strings are equal, false otherwise + */ +bool strncmp(char const *str1, char const *str2, int length) { + + // Check if the strings are equal + for (int i = 0; i < length; i++) + if (str1[i] != str2[i]) + return false; + + // Strings are equal + return true; + +} + +bool strncmp(char const *str1, String const &str2, int length) { + + // Use the other strncmp function + return strncmp(str1, str2.c_str(), length); + +} + +bool strncmp(String const &str1, char const *str2, int length) { + + // Use the other strncmp function + return strncmp(str1.c_str(), str2, length); + +} + +bool strncmp(String const &str1, String const &str2, int length) { + + // Use the other strncmp function + return strncmp(str1.c_str(), str2.c_str(), length); +} diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp new file mode 100644 index 00000000..ff7448aa --- /dev/null +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -0,0 +1,81 @@ +// +// Created by 98max on 18/01/2024. +// +#include +#include + +using namespace MaxOS; +using namespace MaxOS::hardwarecommunication; +using namespace MaxOS::system; +AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(system::Multiboot* multiboot) { + + if(multiboot->get_old_acpi() != 0){ + + // Get the RSDP & RSDT + RSDPDescriptor* rsdp = (RSDPDescriptor*) multiboot->get_old_acpi(); + m_rsdt = (RSDT*) rsdp->rsdt_address; + + // Load the header + m_header = &m_rsdt->header; + + // Check if the checksum is valid + if(!validate((char*) m_rsdt, m_header->length)) + _kprintf("ACPI: Invalid checksum!\n"); + + }else{ + + // Its the new ACPI + m_type = 1; + + // Get the RSDP & XSDT + RSDPDescriptor2* rsdp = (RSDPDescriptor2*) multiboot->get_new_acpi(); + m_xsdt = (XSDT*) rsdp->xsdt_address; + + // Load the header + m_header = &m_xsdt->header; + + // Check if the checksum is valid + if(!validate((char*) m_xsdt, m_header->length)) + _kprintf("ACPI: Invalid checksum!\n"); + + } +} + +AdvancedConfigurationAndPowerInterface::~AdvancedConfigurationAndPowerInterface() { + +} + +bool AdvancedConfigurationAndPowerInterface::validate(char *discriptor, size_t length) { + + // Checksum + uint32_t sum = 0; + + // Calculate the checksum + for(uint32_t i = 0; i < length; i++) + sum += ((char*) discriptor)[i]; + + // Check if the checksum is valid + return ((sum & 0xFF) == 0); + +} + + + +ACPISDTHeader* AdvancedConfigurationAndPowerInterface::find(char const *signature) { + + + // Get the number of entries + size_t entries = (m_header->length - sizeof(ACPISDTHeader)) / 4; + if(m_type) entries = (m_header->length - sizeof(ACPISDTHeader)) / 8; + + // Loop through all the entries + for (int i = 0; i < entries; ++i) { + + // Get the entry + ACPISDTHeader* header = (ACPISDTHeader*) (m_type ? m_xsdt->pointers[i] : m_rsdt->pointers[i]); + + // Check if the signature matches + if(strncmp(header->signature, signature, 4) == 0) + return header; + } +} \ No newline at end of file diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index bb3aa795..8b239bf0 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -6,6 +6,8 @@ //Hardware com #include #include +#include +#include //Drivers #include @@ -106,6 +108,9 @@ void print_boot_header(Console* console){ extern "C" void kernelMain(unsigned long addr, unsigned long magic) { + // Make the multiboot header + Multiboot multiboot(addr); + // Initialise the serial console SerialConsole serialConsole; @@ -120,17 +125,14 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) interrupts.activate(); _kprintf("IDT activated\n"); - asm("int $0x80"); - _kprintf("IDT test completed\n"); + AdvancedConfigurationAndPowerInterface acpi(&multiboot); + _kprintf("ACPI set up\n"); // TODO: 64 bit architecture rewrite while (true) { asm("hlt"); //TODO: This causes a Double Fault and then infinte General Protection Faults } - // Make the multiboot header - Multiboot multiboot(addr); - // Init memory management MemoryManager memoryManager(multiboot.get_mmap()); diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index c8659a77..762c1396 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -30,6 +30,8 @@ Multiboot::Multiboot(unsigned long addr) { m_mmap = (multiboot_tag_mmap *)tag; break; + + } } } @@ -62,3 +64,14 @@ multiboot_tag_mmap *Multiboot::get_mmap() { return m_mmap; } + +multiboot_tag_old_acpi *Multiboot::get_old_acpi() { + + return m_old_acpi; +} + + +multiboot_tag_new_acpi *Multiboot::get_new_acpi() { + + return m_new_acpi; +} From 3d65c395f88c2fa0074e6b28e7393cd9a165247d Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 18 Jan 2024 22:29:26 +1300 Subject: [PATCH 06/29] APIC --- kernel/include/hardwarecommunication/apic.h | 125 ++++++++ kernel/include/system/cpu.h | 67 ++-- kernel/include/system/gdt.h | 2 +- kernel/src/asm/loader.s | 14 +- kernel/src/hardwarecommunication/apic.cpp | 296 ++++++++++++++++++ .../src/hardwarecommunication/interrupts.cpp | 34 ++ kernel/src/kernel.cpp | 10 +- kernel/src/system/cpu.cpp | 74 +++++ kernel/src/system/gdt.cpp | 2 +- 9 files changed, 582 insertions(+), 42 deletions(-) create mode 100644 kernel/include/hardwarecommunication/apic.h create mode 100644 kernel/src/hardwarecommunication/apic.cpp create mode 100644 kernel/src/system/cpu.cpp diff --git a/kernel/include/hardwarecommunication/apic.h b/kernel/include/hardwarecommunication/apic.h new file mode 100644 index 00000000..fd69c938 --- /dev/null +++ b/kernel/include/hardwarecommunication/apic.h @@ -0,0 +1,125 @@ +// +// Created by 98max on 18/01/2024. +// + +#ifndef MAXOS_HARDWARECOMMUNICATION_APIC_H +#define MAXOS_HARDWARECOMMUNICATION_APIC_H + +#include +#include +#include + +namespace MaxOS { + namespace hardwarecommunication { + + + class LocalAPIC { + + protected: + uint64_t m_apic_base; + uint32_t m_id; + bool m_x2apic; + + uint32_t read(uint32_t reg); + void write(uint32_t reg, uint32_t value); + + public: + LocalAPIC(); + ~LocalAPIC(); + + void init(); + + uint32_t id(); + + }; + + struct MADT { + ACPISDTHeader header; + uint32_t local_apic_address; + uint32_t flags; + } __attribute__((packed)); + + struct MADT_Item { + uint8_t type; + uint8_t length; + } __attribute__((packed)); + + struct MADT_IOAPIC { + uint8_t io_apic_id; + uint8_t reserved; + uint32_t io_apic_address; + uint32_t global_system_interrupt_base; + } __attribute__((packed)); + + union RedirectionEntry { + struct { + uint64_t vector : 8; + uint64_t delivery_mode : 3; + uint64_t destination_mode : 1; + uint64_t delivery_status : 1; + uint64_t pin_polarity : 1; + uint64_t remote_irr : 1; + uint64_t trigger_mode : 1; + uint64_t mask : 1; + uint64_t reserved : 39; + uint64_t destination : 8; + } __attribute__((packed)); + + uint64_t raw; + }; + + struct Override { + uint8_t bus; + uint8_t source; + uint32_t global_system_interrupt; + uint16_t flags; + } __attribute__((packed)); + + class IOAPIC { + private: + AdvancedConfigurationAndPowerInterface* m_acpi; + MADT* m_madt; + uint32_t m_address; + uint32_t m_version; + uint8_t m_max_redirect_entry; + + uint32_t m_override_array_size; + Override m_override_array[0x10]; + + MADT_Item* get_madt_item(uint8_t type, uint8_t index); + + uint32_t read(uint32_t reg); + void write(uint32_t reg, uint32_t value); + + void read_redirect(uint8_t index, RedirectionEntry* entry); + void write_redirect(uint8_t index, RedirectionEntry* entry); + + public: + IOAPIC(AdvancedConfigurationAndPowerInterface* acpi); + ~IOAPIC(); + + void init(); + }; + + class AdvancedProgrammableInterruptController { + + protected: + LocalAPIC m_local_apic; + IOAPIC m_io_apic; + + Port8BitSlow m_pic_master_command_port; + Port8BitSlow m_pic_master_data_port; + Port8BitSlow m_pic_slave_command_port; + Port8BitSlow m_pic_slave_data_port; + + void disable_pic(); + + public: + AdvancedProgrammableInterruptController(AdvancedConfigurationAndPowerInterface* acpi); + ~AdvancedProgrammableInterruptController(); + }; + + } +} + +#endif // MAXOS_HARDWARECOMMUNICATION_APIC_H diff --git a/kernel/include/system/cpu.h b/kernel/include/system/cpu.h index 83659bdb..aa2067eb 100644 --- a/kernel/include/system/cpu.h +++ b/kernel/include/system/cpu.h @@ -5,39 +5,54 @@ #ifndef MAXOS_SYSTEM_CPU_H #define MAXOS_SYSTEM_CPU_H +#include +#include + namespace MaxOS{ namespace system{ - typedef struct { - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rdi; - uint64_t rsi; - uint64_t rbp; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t rax; - - uint64_t interrupt_number; - uint64_t error_code; - - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t rsp; - uint64_t ss; - } __attribute__((__packed__)) cpu_status_t ; + typedef struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + uint64_t interrupt_number; + uint64_t error_code; + + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; + } __attribute__((__packed__)) cpu_status_t ; + + class CPU { + public: + static void halt(); + static void get_status(cpu_status_t* status); + static void set_status(cpu_status_t* status); + static uint64_t read_msr(uint32_t msr); + static void write_msr(uint32_t msr, uint64_t value); + static void cpuid(uint32_t leaf, uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx); + }; } } + + #endif // MAXOS_SYSTEM_CPU_H diff --git a/kernel/include/system/gdt.h b/kernel/include/system/gdt.h index 500a83a1..3ffe0b3e 100644 --- a/kernel/include/system/gdt.h +++ b/kernel/include/system/gdt.h @@ -27,7 +27,7 @@ namespace MaxOS { */ class GlobalDescriptorTable { - uint64_t m_gdt[4]; + uint64_t m_gdt[5]; public: GlobalDescriptorTable(); diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index 6fdbb70d..b29407b0 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -147,19 +147,7 @@ p3_table_hh: resb 4096 p2_table: resb 4096 -%ifdef SMALL_PAGES -; if SMALL_PAGES is defined it means we are using 4k pages -; For now the first 8mb will be mapped for the kernel. -; This part is not implemented yet -pt1_table: - resb 4096 -pt2_table: - resb 4096 -pt3_table: - resb 4096 -pt4_table: - resb 4096 -%endif + ; This section is temporary to test the framebuffer align 4096 fbb_p3_table: diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp new file mode 100644 index 00000000..2d9b08ee --- /dev/null +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -0,0 +1,296 @@ +// +// Created by 98max on 18/01/2024. +// +#include +#include + +using namespace MaxOS; +using namespace MaxOS::hardwarecommunication; +using namespace MaxOS::system; + +LocalAPIC::LocalAPIC() { + +} + +LocalAPIC::~LocalAPIC() { + +} + +void LocalAPIC::init() { + + // Read information about the local APIC + uint64_t msr_info = CPU::read_msr(0x1B); + + // Get the APIC base address + m_apic_base = msr_info & 0xFFFFF000; + + // Read if the APIC supports x2APIC + uint32_t ignored, xleaf, x2leaf; + CPU::cpuid(0x0B, ignored, xleaf, x2leaf, ignored); + + if(x2leaf & (1 << 21)) { + + // Enable x2APIC + m_x2apic = true; + msr_info |= (1 << 10); + CPU::write_msr(0x1B, msr_info); + _kprintf("CPU supports x2APIC\n"); + + } else if (xleaf & (1 << 9)) { + + m_x2apic = false; + _kprintf("CPU supports xAPIC\n"); + + } else { + _kprintf("ERROR: CPU does not support APIC (BAD!!)\n"); + } + + // Get the vector table & version + uint32_t spurious_vector = read(0xF0); + uint32_t version = read(0x30); + + // Enable the APIC + write(0xF0, (1 << 8) | 0x100); + + // Log the APIC information + _kprintf("APIC Version: 0x%x\n", version & 0xFF); + _kprintf("APIC Spurious Vector: 0x%x\n", spurious_vector & 0xFF); + +} + +uint32_t LocalAPIC::read(uint32_t reg) { + + // If x2APIC is enabled, use the x2APIC MSR + if(m_x2apic) { + return CPU::read_msr(0x800 + reg); + } else { + return (*(volatile uint32_t*)(m_apic_base + reg)); + } + +} + +void LocalAPIC::write(uint32_t reg, uint32_t value) { + + // If x2APIC is enabled, use the x2APIC MSR + if(m_x2apic) { + CPU::write_msr(0x800 + reg, value); + } else { + (*(volatile uint32_t*)(m_apic_base + reg)) = value; + } +} + +uint32_t LocalAPIC::id() { + + // Read the id + uint32_t id = read(0x20); + + // Return the id + return m_x2apic ? id : (id >> 24); + +} + +IOAPIC::IOAPIC(AdvancedConfigurationAndPowerInterface* acpi) +: m_acpi(acpi), + m_madt(nullptr) +{ + +} + +IOAPIC::~IOAPIC() { + +} + +void IOAPIC::init() { + + // Get the information about the IO APIC + m_madt = (MADT*)m_acpi->find("APIC"); + MADT_Item* io_apic_item = get_madt_item(1, 0); + + // Check if the IO APIC was found + if(io_apic_item == nullptr) { + _kprintf("ERROR: IO APIC not found\n"); + return; + } + + // Get the IO APIC address + MADT_IOAPIC* io_apic = (MADT_IOAPIC*)io_apic_item; + m_address = io_apic->io_apic_address; + + // Get the IO APIC version and max redirection entry + m_version = read(0x01); + m_max_redirect_entry = (uint8_t)(m_version >> 16); + + // Log the IO APIC information + _kprintf("IO APIC Version: 0x%x\n", m_version); + _kprintf("IO APIC Max Redirection Entry: 0x%x\n", m_max_redirect_entry); + + // Get the source override item + MADT_Item* source_override_item = get_madt_item(2, m_override_array_size); + + // Loop through the source override items + uint32_t total_length = 0; + while (total_length < m_madt->header.length && m_override_array_size < 0x10){ // 0x10 is the max items + + // Increment the total length + total_length += source_override_item->length; + + // If there is an override, populate the array + if(source_override_item != nullptr && source_override_item->type == 2) { + + // Get the override and populate the array + Override *override = (Override *)(source_override_item + 1); + m_override_array[m_override_array_size].bus = override->bus; + m_override_array[m_override_array_size].source = override->source; + m_override_array[m_override_array_size].global_system_interrupt = + override->global_system_interrupt; + m_override_array[m_override_array_size].flags = override->flags; + + // Increment the override array size + m_override_array_size++; + } + + // Get the next item + source_override_item = get_madt_item(2, m_override_array_size); + + // If there is no next item then break + if(source_override_item == nullptr) + break; + } + + // Log how many overrides were found + _kprintf("IO APIC Source Overrides: 0x%x\n", m_override_array_size); +} + +MADT_Item *IOAPIC::get_madt_item(uint8_t type, uint8_t index) { + + // The item starts at the start of the MADT + MADT_Item* item = (MADT_Item*)((uint64_t)m_madt + sizeof(MADT)); + uint64_t total_length = 0; + uint8_t current_index = 0; + + // Loop through the items + while (total_length+ sizeof(MADT) < m_madt->header.length && current_index <= index) { + + // Check if the item is the correct type + if(item->type == type) { + + // Check if the item is the correct index + if(current_index == index) { + return item; + } + + // Increment the index + current_index++; + } + + // Increment the total length + total_length += item->length; + + // Increment the item + item = (MADT_Item*)((uint64_t)item + item->length); + } + + // Return null if the item was not found + return nullptr; +} + +uint32_t IOAPIC::read(uint32_t reg) { + + // Write the register + *(volatile uint32_t*)(m_address + 0x00) = reg; + + // Return the value + return *(volatile uint32_t*)(m_address + 0x10); + + +} + +void IOAPIC::write(uint32_t reg, uint32_t value) { + + // Write the register + *(volatile uint32_t*)(m_address + 0x00) = reg; + + // Write the value + *(volatile uint32_t*)(m_address + 0x10) = value; +} + +void IOAPIC::read_redirect(uint8_t index, RedirectionEntry *entry) { + + // If the index is out of bounds, return + if(index < 0x10 || index > 0x3F) + return; + + // Low and high registers + uint32_t low = read(index); + uint32_t high = read(index + 1); + + // Set the entry + entry->raw = ((uint64_t)high << 32) | ((uint64_t)low); + +} + +void IOAPIC::write_redirect(uint8_t index, RedirectionEntry *entry) { + + // If the index is out of bounds, return + if(index < 0x10 || index > 0x3F) + return; + + // Low and high registers + uint32_t low = (uint32_t)entry->raw; + uint32_t high = (uint32_t)(entry->raw >> 32); + + // Set the entry + write(index, low); + write(index + 1, high); +} + +AdvancedProgrammableInterruptController::AdvancedProgrammableInterruptController(AdvancedConfigurationAndPowerInterface* acpi) +: m_local_apic(), + m_io_apic(acpi), + m_pic_master_command_port(0x20), + m_pic_master_data_port(0x21), + m_pic_slave_command_port(0xA0), + m_pic_slave_data_port(0xA1) +{ + + // Init the Local APIC + _kprintf("Initialising Local APIC\n"); + m_local_apic.init(); + + // Disable the old PIC + _kprintf("Disabling PIC\n"); + disable_pic(); + + // Init the IO APIC + _kprintf("Initialising IO APIC\n"); + m_io_apic.init(); + +} + +AdvancedProgrammableInterruptController::~AdvancedProgrammableInterruptController() { + +} + +void AdvancedProgrammableInterruptController::disable_pic() { + + // Initialise the PIC + m_pic_master_command_port.write(0x11); + m_pic_slave_command_port.write(0x11); + + // Set the offsets + m_pic_master_data_port.write(0x20); + m_pic_slave_data_port.write(0x28); + + // Set the slave/master relationships + m_pic_master_data_port.write(0x04); + m_pic_slave_data_port.write(0x02); + + // Set the modes (8086/8086) + m_pic_master_data_port.write(0x01); + m_pic_slave_data_port.write(0x01); + + // Mask the interrupts + m_pic_master_data_port.write(0xFF); + m_pic_slave_data_port.write(0xFF); + +} \ No newline at end of file diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index 3cdb4d63..b240b67d 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -267,6 +267,40 @@ cpu_status_t* InterruptManager::handle_interrupt_request(cpu_status_t* status) { else _kprintf("Unhandled Interrupt: 0x%x\n", status->interrupt_number); + // Debug the General Protection Fault + if(status->interrupt_number == 0x0D) { + + // Define masks for each field + uint32_t E_MASK = 0b10000000000000000000000000000000; + uint32_t Tbl_MASK = 0b01100000000000000000000000000000; + uint32_t Index_MASK = 0b00011111111111110000000000000000; + + // Use bit shifting and masking to extract values + int E = (status -> error_code & E_MASK) >> 31; + int Tbl = (status -> error_code & Tbl_MASK) >> 29; + int Index = (status -> error_code & Index_MASK) >> 16; + + // If bit 0 is set, the exception was caused by external event + _kprintf("General Protection Fault: External Event: %s\n", (E) ? "Yes" : "No"); + + switch(Tbl) { + case 0b00: _kprintf("General Protection Fault: Table: GDT\n"); break; + case 0b01: _kprintf("General Protection Fault: Table: IDT\n"); break; + case 0b10: _kprintf("General Protection Fault: Table: LDT\n"); break; + case 0b11: _kprintf("General Protection Fault: Table: IDT\n"); break; + } + + // Find the selector index (next 13 bits) + _kprintf("General Protection Fault: Selector Index: 0x%x\n", Index); + + // Hang + while(true); + } + + + //TODO: Send SMP interrupt + //todo: send eoi + // Return the status return status; } \ No newline at end of file diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 8b239bf0..fe18d154 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -39,6 +39,7 @@ //SYSTEM #include +#include #include #include #include @@ -128,13 +129,20 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("ACPI set up\n"); + AdvancedProgrammableInterruptController apic(&acpi); + _kprintf("APIC set up\n"); + + // TODO: 64 bit architecture rewrite while (true) { - asm("hlt"); //TODO: This causes a Double Fault and then infinte General Protection Faults + //TODO: This causes a Double Fault and then infinte General Protection Faults + system::CPU::halt(); } // Init memory management MemoryManager memoryManager(multiboot.get_mmap()); + // TODO: Alot needs to be page mapped and higher halfed + // Initialise the VESA Driver VideoElectronicsStandardsAssociation vesa(multiboot.get_framebuffer()); diff --git a/kernel/src/system/cpu.cpp b/kernel/src/system/cpu.cpp new file mode 100644 index 00000000..07c6aadc --- /dev/null +++ b/kernel/src/system/cpu.cpp @@ -0,0 +1,74 @@ +// +// Created by 98max on 18/01/2024. +// +#include + +void MaxOS::system::CPU::halt() { + asm volatile("hlt"); +} + +void MaxOS::system::CPU::get_status(MaxOS::system::cpu_status_t *status) { + + // Get the registers + asm volatile("mov %%r15, %0" : "=r" (status->r15)); + asm volatile("mov %%r14, %0" : "=r" (status->r14)); + asm volatile("mov %%r13, %0" : "=r" (status->r13)); + asm volatile("mov %%r12, %0" : "=r" (status->r12)); + asm volatile("mov %%r11, %0" : "=r" (status->r11)); + asm volatile("mov %%r10, %0" : "=r" (status->r10)); + asm volatile("mov %%r9, %0" : "=r" (status->r9)); + asm volatile("mov %%r8, %0" : "=r" (status->r8)); + asm volatile("mov %%rdi, %0" : "=r" (status->rdi)); + asm volatile("mov %%rsi, %0" : "=r" (status->rsi)); + asm volatile("mov %%rbp, %0" : "=r" (status->rbp)); + asm volatile("mov %%rdx, %0" : "=r" (status->rdx)); + asm volatile("mov %%rcx, %0" : "=r" (status->rcx)); + asm volatile("mov %%rbx, %0" : "=r" (status->rbx)); + asm volatile("mov %%rax, %0" : "=r" (status->rax)); + +} +void MaxOS::system::CPU::set_status(MaxOS::system::cpu_status_t *status) { + + // Set the registers + asm volatile("mov %0, %%r15" : : "r" (status->r15)); + asm volatile("mov %0, %%r14" : : "r" (status->r14)); + asm volatile("mov %0, %%r13" : : "r" (status->r13)); + asm volatile("mov %0, %%r12" : : "r" (status->r12)); + asm volatile("mov %0, %%r11" : : "r" (status->r11)); + asm volatile("mov %0, %%r10" : : "r" (status->r10)); + asm volatile("mov %0, %%r9" : : "r" (status->r9)); + asm volatile("mov %0, %%r8" : : "r" (status->r8)); + asm volatile("mov %0, %%rdi" : : "r" (status->rdi)); + asm volatile("mov %0, %%rsi" : : "r" (status->rsi)); + asm volatile("mov %0, %%rbp" : : "r" (status->rbp)); + asm volatile("mov %0, %%rdx" : : "r" (status->rdx)); + asm volatile("mov %0, %%rcx" : : "r" (status->rcx)); + asm volatile("mov %0, %%rbx" : : "r" (status->rbx)); + asm volatile("mov %0, %%rax" : : "r" (status->rax)); + +} + +uint64_t MaxOS::system::CPU::read_msr(uint32_t msr) { + + // Low and high parts of the MSR + uint32_t low, high; + + // Read the MSR + asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); + + // Return the value + return (uint64_t) low | ((uint64_t) high << 32); + +} + +void MaxOS::system::CPU::write_msr(uint32_t msr, uint64_t value) { + + // Write the MSR + asm volatile("wrmsr" : : "a" ((uint32_t) value), "d" ((uint32_t) (value >> 32)), "c" (msr)); + +} +void MaxOS::system::CPU::cpuid(uint32_t leaf, uint32_t &eax, uint32_t &ebx,uint32_t &ecx, uint32_t &edx) { + + // Call the cpuid instruction + __get_cpuid(leaf, &eax, &ebx, &ecx, &edx); +} diff --git a/kernel/src/system/gdt.cpp b/kernel/src/system/gdt.cpp index 29333070..6eca294d 100644 --- a/kernel/src/system/gdt.cpp +++ b/kernel/src/system/gdt.cpp @@ -44,7 +44,7 @@ GlobalDescriptorTable::GlobalDescriptorTable() // Store the GDT in the GDTR GDTR gdtr = { - .limit = 4 * sizeof(uint64_t) - 1, + .limit = 5 * sizeof(uint64_t) - 1, .address = (uint64_t)m_gdt }; From e6afaddda5a5832a88d6903515ad97a6896335de Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Fri, 19 Jan 2024 12:47:06 +1300 Subject: [PATCH 07/29] Debug --- CMakeLists.txt | 21 ++++++++++++++- filesystem/bin/TEST | 0 filesystem/etc/.gitkeep | 0 filesystem/home/.gitkeep | 0 filesystem/lib/.gitkeep | 0 filesystem/media/.gitkeep | 0 filesystem/opt/.gitkeep | 0 filesystem/{bin => os}/.gitkeep | 0 filesystem/tmp/.gitkeep | 0 filesystem/{dev => user}/.gitkeep | 0 filesystem/usr/bin/.gitkeep | 0 filesystem/usr/include/.gitkeep | 0 filesystem/usr/lib/.gitkeep | 0 filesystem/usr/local/.gitkeep | 0 filesystem/usr/share/.gitkeep | 0 filesystem/usr/src/.gitkeep | 0 filesystem/var/.gitkeep | 0 kernel/include/system/cpu.h | 9 ++++++- .../interruptstubs.s | 0 .../src/hardwarecommunication/interrupts.cpp | 7 +++-- kernel/src/kernel.cpp | 1 - kernel/src/system/cpu.cpp | 19 ++++++++++++++ toolchain/copy_filesystem.sh | 12 ++------- toolchain/run_gdb.sh | 26 +++++++++++++++++++ toolchain/run_qemu.sh | 13 +++++++--- 25 files changed, 89 insertions(+), 19 deletions(-) delete mode 100644 filesystem/bin/TEST delete mode 100644 filesystem/etc/.gitkeep delete mode 100644 filesystem/home/.gitkeep delete mode 100644 filesystem/lib/.gitkeep delete mode 100644 filesystem/media/.gitkeep delete mode 100644 filesystem/opt/.gitkeep rename filesystem/{bin => os}/.gitkeep (100%) delete mode 100644 filesystem/tmp/.gitkeep rename filesystem/{dev => user}/.gitkeep (100%) delete mode 100644 filesystem/usr/bin/.gitkeep delete mode 100644 filesystem/usr/include/.gitkeep delete mode 100644 filesystem/usr/lib/.gitkeep delete mode 100644 filesystem/usr/local/.gitkeep delete mode 100644 filesystem/usr/share/.gitkeep delete mode 100644 filesystem/usr/src/.gitkeep delete mode 100644 filesystem/var/.gitkeep rename kernel/src/{hardwarecommunication => asm}/interruptstubs.s (100%) create mode 100755 toolchain/run_gdb.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ecf2ee1..cec2b1cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,4 +48,23 @@ ADD_CUSTOM_TARGET(run # Ensure it runs in the terminal USES_TERMINAL -) \ No newline at end of file +) + +ADD_CUSTOM_TARGET(debug + # Run qemu + COMMENT "Running qemu" + COMMAND ${CMAKE_COMMAND} -E env "SOURCE_DIR=${CMAKE_SOURCE_DIR}" ${CMAKE_SOURCE_DIR}/toolchain/run_qemu.sh --debug + + # Ensure it runs in the terminal + USES_TERMINAL +) + +ADD_CUSTOM_TARGET(gdb + # Run GDB + COMMENT "Running GDB" + COMMAND ${CMAKE_COMMAND} -E env "SOURCE_DIR=${CMAKE_SOURCE_DIR}" ${CMAKE_SOURCE_DIR}/toolchain/run_gdb.sh + BYPRODUCTS ${CMAKE_SOURCE_DIR}/MaxOS.sym + + # Ensure it runs in the terminal + USES_TERMINAL +) diff --git a/filesystem/bin/TEST b/filesystem/bin/TEST deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/etc/.gitkeep b/filesystem/etc/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/home/.gitkeep b/filesystem/home/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/lib/.gitkeep b/filesystem/lib/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/media/.gitkeep b/filesystem/media/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/opt/.gitkeep b/filesystem/opt/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/bin/.gitkeep b/filesystem/os/.gitkeep similarity index 100% rename from filesystem/bin/.gitkeep rename to filesystem/os/.gitkeep diff --git a/filesystem/tmp/.gitkeep b/filesystem/tmp/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/dev/.gitkeep b/filesystem/user/.gitkeep similarity index 100% rename from filesystem/dev/.gitkeep rename to filesystem/user/.gitkeep diff --git a/filesystem/usr/bin/.gitkeep b/filesystem/usr/bin/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/usr/include/.gitkeep b/filesystem/usr/include/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/usr/lib/.gitkeep b/filesystem/usr/lib/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/usr/local/.gitkeep b/filesystem/usr/local/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/usr/share/.gitkeep b/filesystem/usr/share/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/usr/src/.gitkeep b/filesystem/usr/src/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/filesystem/var/.gitkeep b/filesystem/var/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/kernel/include/system/cpu.h b/kernel/include/system/cpu.h index aa2067eb..67df71be 100644 --- a/kernel/include/system/cpu.h +++ b/kernel/include/system/cpu.h @@ -5,8 +5,9 @@ #ifndef MAXOS_SYSTEM_CPU_H #define MAXOS_SYSTEM_CPU_H -#include #include +#include +#include namespace MaxOS{ @@ -39,6 +40,11 @@ namespace MaxOS{ uint64_t ss; } __attribute__((__packed__)) cpu_status_t ; + struct StackFrame{ + StackFrame* next; + uintptr_t rip; + }; + class CPU { public: static void halt(); @@ -47,6 +53,7 @@ namespace MaxOS{ static uint64_t read_msr(uint32_t msr); static void write_msr(uint32_t msr, uint64_t value); static void cpuid(uint32_t leaf, uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx); + static void stack_trace(size_t); }; } diff --git a/kernel/src/hardwarecommunication/interruptstubs.s b/kernel/src/asm/interruptstubs.s similarity index 100% rename from kernel/src/hardwarecommunication/interruptstubs.s rename to kernel/src/asm/interruptstubs.s diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index b240b67d..ce00ab6a 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -261,8 +261,11 @@ cpu_status_t* InterruptManager::handle_interrupt_request(cpu_status_t* status) { if(m_interrupt_handlers[status -> interrupt_number] != 0) m_interrupt_handlers[status -> interrupt_number]->handle_interrupt(); - else if(status->interrupt_number < m_hardware_interrupt_offset) - _kprintf("Exception: %s\n", exceptions[status->interrupt_number]); + else if(status->interrupt_number < m_hardware_interrupt_offset){ + _kprintf("Exception: %s, Error Code: 0x%x\n", exceptions[status->interrupt_number], status->error_code); + CPU::stack_trace(10); + } + else _kprintf("Unhandled Interrupt: 0x%x\n", status->interrupt_number); diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index fe18d154..e1705714 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -132,7 +132,6 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) AdvancedProgrammableInterruptController apic(&acpi); _kprintf("APIC set up\n"); - // TODO: 64 bit architecture rewrite while (true) { //TODO: This causes a Double Fault and then infinte General Protection Faults diff --git a/kernel/src/system/cpu.cpp b/kernel/src/system/cpu.cpp index 07c6aadc..d1540fce 100644 --- a/kernel/src/system/cpu.cpp +++ b/kernel/src/system/cpu.cpp @@ -2,6 +2,7 @@ // Created by 98max on 18/01/2024. // #include +#include void MaxOS::system::CPU::halt() { asm volatile("hlt"); @@ -72,3 +73,21 @@ void MaxOS::system::CPU::cpuid(uint32_t leaf, uint32_t &eax, uint32_t &ebx,uint3 // Call the cpuid instruction __get_cpuid(leaf, &eax, &ebx, &ecx, &edx); } +void MaxOS::system::CPU::stack_trace(size_t level) { + + // Get the first stack frame + StackFrame* frame = __builtin_frame_address(0); + size_t current_level = 0; + + // Loop through the frames logging + while (current_level < level && frame != nullptr){ + + // Print the frame + _kprintf("(%d);\t at 0x%x\n", current_level, frame->rip); + + // Next frame + frame = frame -> next; + current_level++; + + } +} diff --git a/toolchain/copy_filesystem.sh b/toolchain/copy_filesystem.sh index 37422aed..c4340085 100755 --- a/toolchain/copy_filesystem.sh +++ b/toolchain/copy_filesystem.sh @@ -12,16 +12,8 @@ sudo mv /mnt/MaxOS_img_1/boot/grub.cfg /mnt/MaxOS_img_1/boot/grub/grub.cfg #Copy filesystem msg "Copying filesystem to image" -sudo rm -rf /mnt/MaxOS_img_1/bin && sudo cp -r $SCRIPTDIR/../filesystem/bin /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/dev && sudo cp -r $SCRIPTDIR/../filesystem/dev /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/etc && sudo cp -r $SCRIPTDIR/../filesystem/etc /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/home && sudo cp -r $SCRIPTDIR/../filesystem/home /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/lib && sudo cp -r $SCRIPTDIR/../filesystem/lib /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/media && sudo cp -r $SCRIPTDIR/../filesystem/media /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/opt && sudo cp -r $SCRIPTDIR/../filesystem/opt /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/tmp && sudo cp -r $SCRIPTDIR/../filesystem/tmp /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/usr && sudo cp -r $SCRIPTDIR/../filesystem/usr /mnt/MaxOS_img_1 -sudo rm -rf /mnt/MaxOS_img_1/var && sudo cp -r $SCRIPTDIR/../filesystem/var /mnt/MaxOS_img_1 +sudo rm -rf /mnt/MaxOS_img_1/os && sudo cp -r $SCRIPTDIR/../filesystem/os /mnt/MaxOS_img_1 +sudo rm -rf /mnt/MaxOS_img_1/user && sudo cp -r $SCRIPTDIR/../filesystem/user /mnt/MaxOS_img_1 # Sync filesystem msg "Syncing filesystem" diff --git a/toolchain/run_gdb.sh b/toolchain/run_gdb.sh new file mode 100755 index 00000000..5131f929 --- /dev/null +++ b/toolchain/run_gdb.sh @@ -0,0 +1,26 @@ +#!/bin/bash +SCRIPTDIR=$(dirname "$BASH_SOURCE") +source $SCRIPTDIR/MaxOS.sh + +# Generate the debug symbols +objcopy --only-keep-debug $SCRIPTDIR/../filesystem/boot/MaxOSk64 ../MaxOS.sym +msg "Generated debug symbols" + +# Make the GDB .init file +cat > ~/.gdbinit < Date: Mon, 29 Jan 2024 18:31:11 +1300 Subject: [PATCH 08/29] Various Fixes --- CMakeLists.txt | 2 +- kernel/include/hardwarecommunication/acpi.h | 3 +- kernel/include/memory/memorymanagement.h | 3 ++ kernel/include/system/cpu.h | 2 +- kernel/src/hardwarecommunication/acpi.cpp | 30 ++++++++++++---- kernel/src/hardwarecommunication/apic.cpp | 20 ++++++----- kernel/src/kernel.cpp | 10 +++--- kernel/src/memory/memorymanagement.cpp | 7 ++++ kernel/src/system/cpu.cpp | 5 +-- kernel/src/system/multiboot.cpp | 7 +++- toolchain/run_gdb.sh | 39 +++++++++++++++++---- toolchain/run_qemu.sh | 5 +++ 12 files changed, 99 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cec2b1cc..3ad2a407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ ADD_CUSTOM_TARGET(run ) ADD_CUSTOM_TARGET(debug - # Run qemu + # Run qemu COMMENT "Running qemu" COMMAND ${CMAKE_COMMAND} -E env "SOURCE_DIR=${CMAKE_SOURCE_DIR}" ${CMAKE_SOURCE_DIR}/toolchain/run_qemu.sh --debug diff --git a/kernel/include/hardwarecommunication/acpi.h b/kernel/include/hardwarecommunication/acpi.h index d997ed8d..f878283c 100644 --- a/kernel/include/hardwarecommunication/acpi.h +++ b/kernel/include/hardwarecommunication/acpi.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace MaxOS { namespace hardwarecommunication { @@ -59,7 +60,7 @@ namespace MaxOS { XSDT* m_xsdt; RSDT* m_rsdt; - bool validate(char* discriptor, size_t length); + static bool validate(const char* discriptor, size_t length); public: AdvancedConfigurationAndPowerInterface(system::Multiboot* multiboot); diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index 28481890..ffc0a2c9 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -38,6 +38,7 @@ namespace MaxOS{ public: static MemoryManager* s_active_memory_manager; + static const uint64_t s_higher_half_offset { 0xFFFFFFFF80000000 }; MemoryManager(multiboot_tag_mmap* memory_map); ~MemoryManager(); @@ -45,6 +46,8 @@ namespace MaxOS{ void* malloc(size_t size); void free(void* pointer); int memory_used(); + + static uint64_t map_to_higher_half(uint64_t physical_address); }; } } diff --git a/kernel/include/system/cpu.h b/kernel/include/system/cpu.h index 67df71be..99c706a7 100644 --- a/kernel/include/system/cpu.h +++ b/kernel/include/system/cpu.h @@ -52,7 +52,7 @@ namespace MaxOS{ static void set_status(cpu_status_t* status); static uint64_t read_msr(uint32_t msr); static void write_msr(uint32_t msr, uint64_t value); - static void cpuid(uint32_t leaf, uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx); + static void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx); static void stack_trace(size_t); }; diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index ff7448aa..5b7790f7 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -7,35 +7,52 @@ using namespace MaxOS; using namespace MaxOS::hardwarecommunication; using namespace MaxOS::system; +using namespace MaxOS::memory; AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(system::Multiboot* multiboot) { if(multiboot->get_old_acpi() != 0){ // Get the RSDP & RSDT - RSDPDescriptor* rsdp = (RSDPDescriptor*) multiboot->get_old_acpi(); + RSDPDescriptor* rsdp = (RSDPDescriptor*)(multiboot->get_old_acpi() + 1); m_rsdt = (RSDT*) rsdp->rsdt_address; // Load the header m_header = &m_rsdt->header; + // Calculate the checksum + uint8_t sum = 0; + for(uint32_t i = 0; i < sizeof(RSDPDescriptor); i++) + sum += ((char*)rsdp)[i]; + // Check if the checksum is valid - if(!validate((char*) m_rsdt, m_header->length)) + if(sum != 0) _kprintf("ACPI: Invalid checksum!\n"); }else{ + // If the new ACPI is not supported, panic + if(multiboot->get_new_acpi() == 0){ + _kprintf("ACPI: No ACPI found! (BAD)\n"); + return; + } + // Its the new ACPI m_type = 1; // Get the RSDP & XSDT - RSDPDescriptor2* rsdp = (RSDPDescriptor2*) multiboot->get_new_acpi(); - m_xsdt = (XSDT*) rsdp->xsdt_address; + RSDPDescriptor2* rsdp2 = (RSDPDescriptor2*)(multiboot->get_new_acpi() + 1); + m_xsdt = (XSDT*) rsdp2->xsdt_address; // Load the header m_header = &m_xsdt->header; + // Calculate the checksum + uint8_t sum = 0; + for(uint32_t i = 0; i < sizeof(RSDPDescriptor2); i++) + sum += ((char*)rsdp2)[i]; + // Check if the checksum is valid - if(!validate((char*) m_xsdt, m_header->length)) + if(sum != 0) _kprintf("ACPI: Invalid checksum!\n"); } @@ -45,8 +62,7 @@ AdvancedConfigurationAndPowerInterface::~AdvancedConfigurationAndPowerInterface( } -bool AdvancedConfigurationAndPowerInterface::validate(char *discriptor, size_t length) { - +bool AdvancedConfigurationAndPowerInterface::validate(const char* discriptor, size_t length) { // Checksum uint32_t sum = 0; diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index 2d9b08ee..834d91ef 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -26,7 +26,7 @@ void LocalAPIC::init() { // Read if the APIC supports x2APIC uint32_t ignored, xleaf, x2leaf; - CPU::cpuid(0x0B, ignored, xleaf, x2leaf, ignored); + CPU::cpuid(0x01, &ignored, &ignored, &x2leaf, &xleaf); if(x2leaf & (1 << 21)) { @@ -45,16 +45,18 @@ void LocalAPIC::init() { _kprintf("ERROR: CPU does not support APIC (BAD!!)\n"); } - // Get the vector table & version + // Get the vector table uint32_t spurious_vector = read(0xF0); - uint32_t version = read(0x30); + _kprintf("APIC Spurious Vector: 0x%x\n", spurious_vector & 0xFF); // Enable the APIC write(0xF0, (1 << 8) | 0x100); + _kprintf("APIC Enabled\n"); - // Log the APIC information + // Read the APIC version + uint32_t version = read(0x30); _kprintf("APIC Version: 0x%x\n", version & 0xFF); - _kprintf("APIC Spurious Vector: 0x%x\n", spurious_vector & 0xFF); + } @@ -62,9 +64,9 @@ uint32_t LocalAPIC::read(uint32_t reg) { // If x2APIC is enabled, use the x2APIC MSR if(m_x2apic) { - return CPU::read_msr(0x800 + reg); + return (uint32_t)CPU::read_msr((reg >> 4) + 0x800); } else { - return (*(volatile uint32_t*)(m_apic_base + reg)); + return (*(volatile uint32_t*)((uintptr_t)m_apic_base + reg)); } } @@ -73,9 +75,9 @@ void LocalAPIC::write(uint32_t reg, uint32_t value) { // If x2APIC is enabled, use the x2APIC MSR if(m_x2apic) { - CPU::write_msr(0x800 + reg, value); + CPU::write_msr((reg >> 4) + 0x800, value); } else { - (*(volatile uint32_t*)(m_apic_base + reg)) = value; + (*(volatile uint32_t*)((uintptr_t)m_apic_base + reg)) = value; } } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index e1705714..0cedf9ad 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -117,21 +117,21 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("MaxOS booted\n"); - GlobalDescriptorTable gdt; - _kprintf("GDT set up\n"); + //GlobalDescriptorTable gdt; + //_kprintf("GDT set up\n"); InterruptManager interrupts(0x20, 0); _kprintf("IDT set up\n"); - interrupts.activate(); - _kprintf("IDT activated\n"); - AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("ACPI set up\n"); AdvancedProgrammableInterruptController apic(&acpi); _kprintf("APIC set up\n"); + interrupts.activate(); + _kprintf("IDT activated\n"); + // TODO: 64 bit architecture rewrite while (true) { //TODO: This causes a Double Fault and then infinte General Protection Faults diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index 424392f0..3b1fbf0f 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -157,8 +157,15 @@ int MemoryManager::memory_used() { return result; } +uint64_t MemoryManager::map_to_higher_half(uint64_t physical_address) { + // Check if the address is already mapped + if(physical_address >= s_higher_half_offset) + return physical_address; + // Map the address to the higher half + return physical_address + s_higher_half_offset; +} //Redefine the default object functions with memory orientated ones (defaults disabled in makefile) diff --git a/kernel/src/system/cpu.cpp b/kernel/src/system/cpu.cpp index d1540fce..61ecc415 100644 --- a/kernel/src/system/cpu.cpp +++ b/kernel/src/system/cpu.cpp @@ -68,11 +68,12 @@ void MaxOS::system::CPU::write_msr(uint32_t msr, uint64_t value) { asm volatile("wrmsr" : : "a" ((uint32_t) value), "d" ((uint32_t) (value >> 32)), "c" (msr)); } -void MaxOS::system::CPU::cpuid(uint32_t leaf, uint32_t &eax, uint32_t &ebx,uint32_t &ecx, uint32_t &edx) { +void MaxOS::system::CPU::cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { // Call the cpuid instruction - __get_cpuid(leaf, &eax, &ebx, &ecx, &edx); + __get_cpuid(leaf, eax, ebx, ecx, edx); } + void MaxOS::system::CPU::stack_trace(size_t level) { // Get the first stack frame diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index 762c1396..1550d1e0 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -30,8 +30,13 @@ Multiboot::Multiboot(unsigned long addr) { m_mmap = (multiboot_tag_mmap *)tag; break; + case MULTIBOOT_TAG_TYPE_ACPI_OLD: + m_old_acpi = (multiboot_tag_old_acpi *)tag; + break; - + case MULTIBOOT_TAG_TYPE_ACPI_NEW: + m_new_acpi = (multiboot_tag_new_acpi *)tag; + break; } } } diff --git a/toolchain/run_gdb.sh b/toolchain/run_gdb.sh index 5131f929..274c7124 100755 --- a/toolchain/run_gdb.sh +++ b/toolchain/run_gdb.sh @@ -2,19 +2,44 @@ SCRIPTDIR=$(dirname "$BASH_SOURCE") source $SCRIPTDIR/MaxOS.sh -# Generate the debug symbols -objcopy --only-keep-debug $SCRIPTDIR/../filesystem/boot/MaxOSk64 ../MaxOS.sym -msg "Generated debug symbols" +IP=localhost +IN_WSL=0 +if command -v wslpath >/dev/null; then + msg "WSL detected." + + # Get the ip from ipconfig.exe + LOCAL_IP=${LOCAL_IP:-`ipconfig.exe | grep -im1 'IPv4 Address' | cut -d ':' -f2`} + + echo "WSL IP is: ${LOCAL_IP}" + IP=${LOCAL_IP} + + # Strip the carriage return + IP=${IP%$'\r'} +fi + # Make the GDB .init file cat > ~/.gdbinit < Date: Mon, 29 Jan 2024 20:40:31 +1300 Subject: [PATCH 09/29] Update Clock Driver --- kernel/include/drivers/clock/clock.h | 3 ++- kernel/src/drivers/clock/clock.cpp | 40 +++++++++++++--------------- kernel/src/kernel.cpp | 2 ++ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/kernel/include/drivers/clock/clock.h b/kernel/include/drivers/clock/clock.h index bf8681cd..0c254645 100644 --- a/kernel/include/drivers/clock/clock.h +++ b/kernel/include/drivers/clock/clock.h @@ -60,7 +60,8 @@ namespace MaxOS { protected: - bool m_binary_coded_decimal_representation; + bool m_binary; + bool m_24_hour_clock; // Ports hardwarecommunication::Port8Bit m_data_port; diff --git a/kernel/src/drivers/clock/clock.cpp b/kernel/src/drivers/clock/clock.cpp index 3a087cd9..836b7a46 100644 --- a/kernel/src/drivers/clock/clock.cpp +++ b/kernel/src/drivers/clock/clock.cpp @@ -57,7 +57,7 @@ Clock::Clock(InterruptManager *interrupt_manager, uint16_t time_between_events) m_data_port(0x71), m_command_port(0x70), m_ticks_between_events(time_between_events) { - + //TODO: Configure APIC Clock } Clock::~Clock() { @@ -81,6 +81,9 @@ void Clock::handle_interrupt() { // Otherwise, reset the number of ticks until the next event m_ticks_until_next_event = m_ticks_between_events; + // Wait for the clock to be ready + while((read_hardware_clock(0xA) & 0x80) != 0); + // Create a time object Time time; @@ -92,6 +95,14 @@ void Clock::handle_interrupt() { time.minute = binary_representation(read_hardware_clock(0x2)); // Register 2 is the minute time.second = binary_representation(read_hardware_clock(0x0)); // Register 0 is the second + // If the clock is using 12hr format and PM is set then add 12 to the hour + if(!m_24_hour_clock && (time.hour & 0x80) != 0) { + + // Convert the time to 24hr format + time.hour = ((time.hour & 0x7F) + 12) % 24; + + } + //Raise the clock event raise_event(new TimeEvent(&time)); } @@ -105,16 +116,6 @@ void Clock::handle_interrupt() { */ uint8_t Clock::read_hardware_clock(uint8_t address) { - // If the address is a time or date register, disable updates - if(address < 10) - { - m_command_port.write(0xa); - - // Wait until any updates are finished - while((m_data_port.read() & (1 << 7)) != 0) - asm volatile("nop"); // execute the "nop" assembly instruction, which does nothing, but prevents the compiler from optimizing away the loop - } - // Send the address to the hardware clock m_command_port.write(address); @@ -131,11 +132,11 @@ uint8_t Clock::read_hardware_clock(uint8_t address) uint8_t Clock::binary_representation(uint8_t number) { // If the binary coded decimal representation is not used, return the number - if(!m_binary_coded_decimal_representation) + if(m_binary) return number; // Otherwise, return the binary representation - return (number & 0xf) + ((number >> 4) & 0xf) * 10; + return ((number / 16) * 10) + (number & 0x0f); } @@ -145,16 +146,11 @@ uint8_t Clock::binary_representation(uint8_t number) { void Clock::activate() { // read the status register - uint8_t status = read_hardware_clock(0xb); - - // If the fourth bit is 0 the binary coded decimal representation is used - m_binary_coded_decimal_representation = (status & 4) == 0; + uint8_t status = read_hardware_clock(0xB); - // Convert status to binary - // 00001011 = 0x0B (status as an example) - // 00000100 = 0x04 (binary mask used to extract fourth bit) - // 00000000 = 0x00 (result of bitwise AND operation with binary mask) - // 00000000 == 0 (check if fourth bit is 0 to determine if BCD is used) + // Set the clock information + m_24_hour_clock = status & 0x02; + m_binary = status & 0x04; } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 0cedf9ad..c8758756 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -123,6 +123,8 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) InterruptManager interrupts(0x20, 0); _kprintf("IDT set up\n"); + // TODO Memory map set up so MEMIO can be used without triggering a page fault + AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("ACPI set up\n"); From debcee3c7fcffb970c90a97cd787e5083deda00d Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Mon, 29 Jan 2024 21:16:07 +1300 Subject: [PATCH 10/29] Clean Up --- kernel/src/common/kprint.cpp | 6 +++--- kernel/src/drivers/video/vesa.cpp | 2 +- kernel/src/gui/widgets/inputbox.cpp | 2 +- kernel/src/hardwarecommunication/acpi.cpp | 5 ++++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/kernel/src/common/kprint.cpp b/kernel/src/common/kprint.cpp index 56281806..b2cf7bd4 100644 --- a/kernel/src/common/kprint.cpp +++ b/kernel/src/common/kprint.cpp @@ -54,7 +54,7 @@ int strlen(const char* str) { int len = 0; for (; str[len] != '\0'; len++); - return len; + return len; } /** @@ -77,7 +77,7 @@ static void putchar (int c) void pre_kprintf() { // Print the kernel header with yellow text - char* header = "\033[1;33m[DEBUG] \033[0m"; + const char* header = "\033[1;33m[DEBUG] \033[0m"; for (int i = 0; i < strlen(header); i++) putchar(header[i]); @@ -103,7 +103,7 @@ void _kprintf (const char *format, ...) // Create a pointer to the data va_list parameters; - va_start (parameters, format); + va_start(parameters, format); // Loop through the format string for (; *format != '\0'; format++) diff --git a/kernel/src/drivers/video/vesa.cpp b/kernel/src/drivers/video/vesa.cpp index a0d958f8..4aeafe67 100644 --- a/kernel/src/drivers/video/vesa.cpp +++ b/kernel/src/drivers/video/vesa.cpp @@ -37,7 +37,7 @@ bool VideoElectronicsStandardsAssociation::init() { * @param color_depth Color depth of the screen * @return True if the mode was set successfully, false otherwise */ -bool VideoElectronicsStandardsAssociation::internal_set_mode(uint32_t width, uint32_t height, uint32_t color_depth) { +bool VideoElectronicsStandardsAssociation::internal_set_mode(uint32_t, uint32_t, uint32_t) { // Best mode is set by the bootloader return true; diff --git a/kernel/src/gui/widgets/inputbox.cpp b/kernel/src/gui/widgets/inputbox.cpp index 6437b1cd..be45ea66 100644 --- a/kernel/src/gui/widgets/inputbox.cpp +++ b/kernel/src/gui/widgets/inputbox.cpp @@ -190,7 +190,7 @@ void InputBox::on_key_down(KeyCode keyDownCode, KeyboardState) { } // Check if we need to make space for the new character - if (length >= m_widget_text.length()) { + if (length >= (uint32_t)m_widget_text.length()) { m_widget_text += " "; } diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index 5b7790f7..af6a2ad5 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -85,7 +85,7 @@ ACPISDTHeader* AdvancedConfigurationAndPowerInterface::find(char const *signatur if(m_type) entries = (m_header->length - sizeof(ACPISDTHeader)) / 8; // Loop through all the entries - for (int i = 0; i < entries; ++i) { + for (size_t i = 0; i < entries; ++i) { // Get the entry ACPISDTHeader* header = (ACPISDTHeader*) (m_type ? m_xsdt->pointers[i] : m_rsdt->pointers[i]); @@ -94,4 +94,7 @@ ACPISDTHeader* AdvancedConfigurationAndPowerInterface::find(char const *signatur if(strncmp(header->signature, signature, 4) == 0) return header; } + + // Return null if no entry was found + return nullptr; } \ No newline at end of file From b3fd0bff53bd021a556d20d371299baed3fa1f33 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Mon, 29 Jan 2024 21:20:51 +1300 Subject: [PATCH 11/29] Fix Workflow --- .github/workflows/max-os.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/max-os.yml b/.github/workflows/max-os.yml index dcbc5aed..4acf9a78 100644 --- a/.github/workflows/max-os.yml +++ b/.github/workflows/max-os.yml @@ -42,6 +42,9 @@ jobs: - name: Build MaxOS (Release) run: | + cd toolchain + ./version.sh --force + cd ../ mkdir -p cmake-build cd cmake-build cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain/CMakeToolchain.txt From 3505a76c82b88e3298dbd4e11e1e8cd23a656ac0 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 3 Feb 2024 22:42:12 +1300 Subject: [PATCH 12/29] Begin Looking at Memory --- kernel/include/memory/pmm.h | 42 +++++++++++++++++++++++++++++++++ kernel/src/asm/loader.s | 30 ----------------------- kernel/src/kernel.cpp | 14 ++++++----- kernel/src/memory/pmm.cpp | 19 +++++++++++++++ kernel/src/system/multiboot.cpp | 9 +++++++ 5 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 kernel/include/memory/pmm.h create mode 100644 kernel/src/memory/pmm.cpp diff --git a/kernel/include/memory/pmm.h b/kernel/include/memory/pmm.h new file mode 100644 index 00000000..2ce65a0e --- /dev/null +++ b/kernel/include/memory/pmm.h @@ -0,0 +1,42 @@ +// +// Created by 98max on 1/30/2024. +// + +#ifndef MAXOS_MEMORY_PMM_H +#define MAXOS_MEMORY_PMM_H + +#include +#include +#include + +namespace MaxOS { + + namespace memory { + + class PhysicalMemoryManager{ + + private: + const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB + const uint8_t ROW_BITS = { 64 }; + + uint64_t* m_bit_map; + uint32_t m_total_entries; + uint32_t m_bitmap_size; + uint32_t m_used_frames; + + public: + + PhysicalMemoryManager(unsigned long reserved, multiboot_tag_basic_meminfo* meminfo); + ~PhysicalMemoryManager(); + + void allocate_frame(size_t size); + void free_frame(void* address); + + void allocate_area(uint64_t start_address, size_t size); + void free_area(uint64_t start_address, size_t size); + }; + } + +} + +#endif // MAXOS_MEMORY_PMM_H diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index b29407b0..32b228f7 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -51,29 +51,6 @@ start: jne .map_p2_table ; if ecx < 512 then loop - ; This section is temporary, is here only to test the framebuffer features! - ; Will be removed once the the memory management will be implemented - mov eax, fbb_p2_table - KERNEL_VIRTUAL_ADDR - or eax, 0b11 - mov dword [(p3_table - KERNEL_VIRTUAL_ADDR)+ 8 * 3], eax - - mov eax, 0xFD000000 - or eax, 0b10000011 - mov dword [(fbb_p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 488], eax - - ; Now time to map the kernel in the higher half - ; mov eax, hhk_p2_table - ; or eax, 0b11 - ; mov dword [fbb_p2_table + 0], eax - - mov eax, 0x000000 ; This is the base address of the kernel - or eax, 0b10000011 - mov dword [(fbb_p2_table - KERNEL_VIRTUAL_ADDR) + 0], eax - - mov eax, 0x200000 - or eax, 0b10000011 - mov dword [(fbb_p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 1], eax ; Multiply by 1 just to highlight the entry number - ; All set... now we are nearly ready to enter into 64 bit ; Is possible to move into cr3 only from another register ; So let's move p4_table address into eax first @@ -148,13 +125,6 @@ p3_table_hh: p2_table: resb 4096 -; This section is temporary to test the framebuffer -align 4096 -fbb_p3_table: - resb 4096 -fbb_p2_table: - resb 4096 - stack: resb 16384 .top: diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index c8758756..ab6ee263 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -45,7 +45,7 @@ #include //MEMORY -#include +#include //FILESYSTEM #include @@ -105,16 +105,16 @@ void print_boot_header(Console* console){ } - +extern uint32_t kernel_end; extern "C" void kernelMain(unsigned long addr, unsigned long magic) { - // Make the multiboot header - Multiboot multiboot(addr); - // Initialise the serial console SerialConsole serialConsole; + // Make the multiboot header + Multiboot multiboot(addr); + _kprintf("MaxOS booted\n"); //GlobalDescriptorTable gdt; @@ -123,7 +123,9 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) InterruptManager interrupts(0x20, 0); _kprintf("IDT set up\n"); - // TODO Memory map set up so MEMIO can be used without triggering a page fault + uint32_t mbi_size = *(uint32_t *) (addr + MemoryManager::s_higher_half_offset); + PhysicalMemoryManager pmm(addr + mbi_size, multiboot.get_basic_meminfo()); + _kprintf("Physical Memory Manager set up \n"); AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("ACPI set up\n"); diff --git a/kernel/src/memory/pmm.cpp b/kernel/src/memory/pmm.cpp new file mode 100644 index 00000000..e8ba386c --- /dev/null +++ b/kernel/src/memory/pmm.cpp @@ -0,0 +1,19 @@ +// +// Created by 98max on 1/30/2024. +// + +#include +#include + +MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, multiboot_tag_basic_meminfo* meminfo){ + + // Store the information about the bitmap + uint64_t memory_size = (meminfo -> mem_upper + 1024) * 1024; + m_total_entries = (memory_size / PAGE_SIZE); + + _kprintf("Found Memory with size of %d bytes\n", memory_size); + _kprintf("Total Pages: %d \n", m_total_entries); + + // Map Kernel + // Reserve the area +} diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index 1550d1e0..e3f5af56 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -3,11 +3,13 @@ // #include +#include using namespace MaxOS; using namespace MaxOS::system; Multiboot::Multiboot(unsigned long addr) { + _kprintf("MUltiboot\n"); // Loop through the tags and load them struct multiboot_tag *tag; @@ -28,6 +30,13 @@ Multiboot::Multiboot(unsigned long addr) { case MULTIBOOT_TAG_TYPE_MMAP: m_mmap = (multiboot_tag_mmap *)tag; + + // Print some debug about the m_mmap information + for (multiboot_mmap_entry *entry = m_mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap + m_mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap->entry_size)) { + if(entry->type == MULTIBOOT_MEMORY_AVAILABLE) + _kprintf("Base Address: 0x%x%x Length: 0x%x%x Type: %d\n", (unsigned)(entry->addr >> 32), (unsigned)(entry->addr & 0xFFFFFFFF), (unsigned)(entry->len >> 32), (unsigned)(entry->len & 0xFFFFFFFF), entry->type); + } + break; case MULTIBOOT_TAG_TYPE_ACPI_OLD: From 9a8f73f9c4791621820c4ee2754d837dda3a77e1 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 8 Feb 2024 17:03:45 +1300 Subject: [PATCH 13/29] Physical Address --- README.md | 1 + kernel/include/memory/pmm.h | 13 ++- kernel/src/kernel.cpp | 2 +- kernel/src/memory/pmm.cpp | 175 ++++++++++++++++++++++++++++++-- kernel/src/system/multiboot.cpp | 7 -- toolchain/run_qemu.sh | 2 +- 6 files changed, 182 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index bc95f7a1..dafcf347 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ Distributed under the BSD 3-Clause License. See `LICENSE` for more information. * [OSDev Notes](https://github.com/dreamportdev/Osdev-Notes/) * [OSDev Subreddit](https://www.reddit.com/r/osdev/) * [Duck OS](https://github.com/byteduck/duckOS) +* [Dream OS](https://github.com/dreamos82/Dreamos64)

(back to top)

diff --git a/kernel/include/memory/pmm.h b/kernel/include/memory/pmm.h index 2ce65a0e..a583fd4e 100644 --- a/kernel/include/memory/pmm.h +++ b/kernel/include/memory/pmm.h @@ -24,16 +24,23 @@ namespace MaxOS { uint32_t m_bitmap_size; uint32_t m_used_frames; + multiboot_mmap_entry* m_mmap; + public: - PhysicalMemoryManager(unsigned long reserved, multiboot_tag_basic_meminfo* meminfo); + PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot); ~PhysicalMemoryManager(); - void allocate_frame(size_t size); + void* allocate_frame(); void free_frame(void* address); - void allocate_area(uint64_t start_address, size_t size); + void* allocate_area(uint64_t start_address, size_t size); void free_area(uint64_t start_address, size_t size); + + // Tools + size_t size_to_frames(size_t size) const; + size_t align_to_page(size_t size) const; + bool check_aligned(size_t size) const; }; } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index ab6ee263..1199ab3d 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -124,7 +124,7 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("IDT set up\n"); uint32_t mbi_size = *(uint32_t *) (addr + MemoryManager::s_higher_half_offset); - PhysicalMemoryManager pmm(addr + mbi_size, multiboot.get_basic_meminfo()); + PhysicalMemoryManager pmm(addr + mbi_size, &multiboot); _kprintf("Physical Memory Manager set up \n"); AdvancedConfigurationAndPowerInterface acpi(&multiboot); diff --git a/kernel/src/memory/pmm.cpp b/kernel/src/memory/pmm.cpp index e8ba386c..5c60afd6 100644 --- a/kernel/src/memory/pmm.cpp +++ b/kernel/src/memory/pmm.cpp @@ -5,15 +5,178 @@ #include #include -MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, multiboot_tag_basic_meminfo* meminfo){ +using namespace MaxOS::memory; +using namespace MaxOS::system; + +MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot){ // Store the information about the bitmap - uint64_t memory_size = (meminfo -> mem_upper + 1024) * 1024; - m_total_entries = (memory_size / PAGE_SIZE); + uint64_t memory_size = (multiboot->get_basic_meminfo() -> mem_upper + 1024) * 1024; + m_bitmap_size = memory_size / PAGE_SIZE; + m_total_entries = m_bitmap_size / ROW_BITS; _kprintf("Found Memory with size of %d bytes\n", memory_size); - _kprintf("Total Pages: %d \n", m_total_entries); + _kprintf("Bitmap Size: %d\n", m_bitmap_size); + _kprintf("Total Entries: %d \n", m_total_entries); + + // Loop through all the memory map entries + multiboot_tag_mmap* mmap = multiboot->get_mmap(); + for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + + // Skip if the region is not free or there is not enough space + if (entry->type != MULTIBOOT_MEMORY_AVAILABLE || + (entry->addr + entry->len) < reserved) + continue; + + m_mmap = entry; + break; + } + + // Check if the reserved area is part of the mmap + size_t offset = 0; + if(reserved > m_mmap -> addr) + offset = reserved - m_mmap -> addr; + + // Use the memory + m_bit_map = (uint64_t *)(m_mmap->addr + offset); + + // Free all the entries + for (uint32_t i = 0; i < m_total_entries; ++i) + m_bit_map[i] = 0; + + // Calculate how much space the kernel takes up + uint32_t kernel_entries = (reserved / PAGE_SIZE) + 1; + if((((uint32_t)(reserved)) % PAGE_SIZE) != 0){ + // This means that there is kernel modules since there is spare space after one page + kernel_entries += 1; + } + + // Reserve the kernel in the bitmap + m_bit_map[kernel_entries / 64] = ~(~(0ul) << (kernel_entries % 64)); + + // Reserve the area for the bitmap + allocate_area((uint64_t)m_bit_map, (m_bitmap_size / 8) + 1); +} + +PhysicalMemoryManager::~PhysicalMemoryManager() { + +} + +size_t PhysicalMemoryManager::size_to_frames(size_t size) const { + return align_to_page(size) / PAGE_SIZE; +} + + +size_t PhysicalMemoryManager::align_to_page(size_t size) const { + return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); +} + +bool PhysicalMemoryManager::check_aligned(size_t size) const { + return (size % PAGE_SIZE) == 0; +} + + +void* PhysicalMemoryManager::allocate_frame() { + + // Check if there are enough frames + if(m_used_frames >= m_bitmap_size) + return nullptr; + + // Loop through the bitmap + for (uint16_t row = 0; row < m_total_entries; ++row) { + for (uint16_t column = 0; column < ROW_BITS; ++column) { + + // Check if this frame is free + if((m_bit_map[row] & (1 << column))) + continue; + + // Mark the frame as used + m_bit_map[row] |= (1 << column); + m_used_frames++; + + // Return the address + uint64_t frame_address = (row * ROW_BITS) + column; + return (void*)(frame_address * PAGE_SIZE); + } + } + + // Error frame not found + return nullptr; + +} + + +void PhysicalMemoryManager::free_frame(void *address) { + + // Mark the frame as not used + m_used_frames--; + + // Set the bit to 0 + uint64_t frame_address = (uint64_t)address / PAGE_SIZE; + m_bit_map[frame_address / ROW_BITS] &= ~(1 << (frame_address % ROW_BITS)); +} + + +void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) { + + // Check how many frames are needed + size_t frame_count = size_to_frames(size); + + // Store the information about the frames needed to be allocated for this size + uint16_t start_row = 0; + uint16_t start_column = 0; + size_t adjacent_frames = 0; + + // Loop through the bitmap + for (uint16_t row = 0; row < m_total_entries; ++row) { + for (uint16_t column = 0; column < ROW_BITS; ++column) { + + // If this bit is not free reset the adjacent frames + if((m_bit_map[row] & (1 << column))){ + adjacent_frames = 0; + continue; + } + + // Store the start of the area if it is not already stored + if(adjacent_frames == 0){ + start_row = row; + start_column = column; + } + + // Increment the adjacent frames + adjacent_frames++; + + // If enough frames are found we can allocate the area + if(adjacent_frames == frame_count){ + + // Mark the frames as used + m_used_frames += frame_count; + for (uint16_t i = 0; i < frame_count; ++i) + m_bit_map[start_row + (start_column + i) / ROW_BITS] |= (1 << ((start_column + i) % ROW_BITS)); + + // Return the address + return (void*)(start_address + (start_row * ROW_BITS + start_column) * PAGE_SIZE); + } + } + } + + // Error cant allocate that much + return nullptr; +} + +void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { + + // Check how many frames are needed + size_t frame_count = size_to_frames(size); + uint64_t frame_address = start_address / PAGE_SIZE; + + // Check if the address is valid + if(frame_address >= m_bitmap_size) + return; + + // Mark the frames as not used + m_used_frames -= frame_count; + for (uint16_t i = 0; i < frame_count; ++i) + m_bit_map[(frame_address + i) / ROW_BITS] &= ~(1 << ((frame_address + i) % ROW_BITS)); - // Map Kernel - // Reserve the area } diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index e3f5af56..7e24646c 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -30,13 +30,6 @@ Multiboot::Multiboot(unsigned long addr) { case MULTIBOOT_TAG_TYPE_MMAP: m_mmap = (multiboot_tag_mmap *)tag; - - // Print some debug about the m_mmap information - for (multiboot_mmap_entry *entry = m_mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap + m_mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap->entry_size)) { - if(entry->type == MULTIBOOT_MEMORY_AVAILABLE) - _kprintf("Base Address: 0x%x%x Length: 0x%x%x Type: %d\n", (unsigned)(entry->addr >> 32), (unsigned)(entry->addr & 0xFFFFFFFF), (unsigned)(entry->len >> 32), (unsigned)(entry->len & 0xFFFFFFFF), entry->type); - } - break; case MULTIBOOT_TAG_TYPE_ACPI_OLD: diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh index ea519ed4..6b394de4 100755 --- a/toolchain/run_qemu.sh +++ b/toolchain/run_qemu.sh @@ -136,7 +136,7 @@ fi # Create the args QEMU_ARGS="" -QEMU_ARGS="$QEMU_ARGS -m 512" # 512 MB of RAM +QEMU_ARGS="$QEMU_ARGS -m 2G" # 512 MB of RAM QEMU_ARGS="$QEMU_ARGS -smp cores=4" # 4 cores QEMU_ARGS="$QEMU_ARGS -serial stdio" # Use stdio for serial if [ ! "$USE_DEBUG" -ne "0" ]; then From 56a0590e04e6fef6de047a3518736ff4837e1b98 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sun, 11 Feb 2024 16:03:07 +1300 Subject: [PATCH 14/29] Change kprintf --- kernel/include/common/kprint.h | 8 +++- kernel/include/memory/{pmm.h => physical.h} | 6 +-- kernel/include/memory/virtual.h | 32 +++++++++++++++ kernel/src/common/kprint.cpp | 45 ++++++++++++++++++--- kernel/src/kernel.cpp | 2 +- kernel/src/memory/{pmm.cpp => physical.cpp} | 2 +- kernel/src/memory/virtual.cpp | 3 ++ 7 files changed, 87 insertions(+), 11 deletions(-) rename kernel/include/memory/{pmm.h => physical.h} (91%) create mode 100644 kernel/include/memory/virtual.h rename kernel/src/memory/{pmm.cpp => physical.cpp} (99%) create mode 100644 kernel/src/memory/virtual.cpp diff --git a/kernel/include/common/kprint.h b/kernel/include/common/kprint.h index ba6fe9ff..15808e85 100644 --- a/kernel/include/common/kprint.h +++ b/kernel/include/common/kprint.h @@ -6,7 +6,13 @@ #define MAXOS_KPRINT_H #include +#include -void _kprintf(const char* format, ...); + +#define _kprintf(format, ...) \ + _kprintf_internal(__FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) + + +void _kprintf_internal(const char* file, int line, const char* func, const char* format, ...); #endif // MAXOS_KPRINT_H diff --git a/kernel/include/memory/pmm.h b/kernel/include/memory/physical.h similarity index 91% rename from kernel/include/memory/pmm.h rename to kernel/include/memory/physical.h index a583fd4e..a0031c69 100644 --- a/kernel/include/memory/pmm.h +++ b/kernel/include/memory/physical.h @@ -2,8 +2,8 @@ // Created by 98max on 1/30/2024. // -#ifndef MAXOS_MEMORY_PMM_H -#define MAXOS_MEMORY_PMM_H +#ifndef MAXOS_MEMORY_PHYSICAL_H +#define MAXOS_MEMORY_PHYSICAL_H #include #include @@ -46,4 +46,4 @@ namespace MaxOS { } -#endif // MAXOS_MEMORY_PMM_H +#endif // MAXOS_MEMORY_PHYSICAL_H diff --git a/kernel/include/memory/virtual.h b/kernel/include/memory/virtual.h new file mode 100644 index 00000000..4b8e6eab --- /dev/null +++ b/kernel/include/memory/virtual.h @@ -0,0 +1,32 @@ +// +// Created by 98max on 2/11/2024. +// + +#ifndef MAXOS_VIRTUAL_H +#define MAXOS_VIRTUAL_H + +#include +#include + +namespace MaxOS { + namespace memory { + + // Useful for readability + typedef void virtual_address_t; + typedef void physical_address_t; + + class VirtualMemoryManager{ + + private: + uint64_t * m_pml4_root_address; + + public: + VirtualMemoryManager(); + ~VirtualMemoryManager(); + + }; + } +} + + +#endif // MAXOS_VIRTUAL_H diff --git a/kernel/src/common/kprint.cpp b/kernel/src/common/kprint.cpp index b2cf7bd4..195bd4e0 100644 --- a/kernel/src/common/kprint.cpp +++ b/kernel/src/common/kprint.cpp @@ -3,7 +3,7 @@ // #include -#include + using namespace MaxOS::drivers; @@ -74,13 +74,48 @@ static void putchar (int c) /** * @ brief Prints a debug prefix (in yellow) to the serial output */ -void pre_kprintf() +void pre_kprintf(const char* file, int line, const char* func) { // Print the kernel header with yellow text - const char* header = "\033[1;33m[DEBUG] \033[0m"; + const char* header = "\033[1;33m["; for (int i = 0; i < strlen(header); i++) putchar(header[i]); + // Print the file (but not the path) + const char* file_str = file; + for (int i = strlen(file) - 1; i >= 0; i--) + { + if (file[i] == '/') + { + file_str = &file[i + 1]; + break; + } + }\ + for (int j = 0; j < strlen(file_str); j++) + putchar(file_str[j]); + putchar(':'); + + + // Print the line + const char* line_str = itoa(10, line); + for (int i = 0; i < strlen(line_str); i++) + putchar(line_str[i]); + + /* Print the spacer + putchar(' '); + putchar('-'); + putchar(' '); + + // Print the function + for (int i = 0; i < strlen(func); i++) + putchar(func[i]); + */ + + // Print the kernel footer + const char* footer = "] \033[0m"; + for (int i = 0; i < strlen(footer); i++) + putchar(footer[i]); + } /** @@ -95,11 +130,11 @@ void pre_kprintf() * @param format The formatted string * @param ... The data to pass into the string */ -void _kprintf (const char *format, ...) +void _kprintf_internal(const char* file, int line, const char* func, const char* format, ...) { // Print the header - pre_kprintf(); + pre_kprintf(file, line,func); // Create a pointer to the data va_list parameters; diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 1199ab3d..7dc207d4 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -45,7 +45,7 @@ #include //MEMORY -#include +#include //FILESYSTEM #include diff --git a/kernel/src/memory/pmm.cpp b/kernel/src/memory/physical.cpp similarity index 99% rename from kernel/src/memory/pmm.cpp rename to kernel/src/memory/physical.cpp index 5c60afd6..74a461cb 100644 --- a/kernel/src/memory/pmm.cpp +++ b/kernel/src/memory/physical.cpp @@ -2,8 +2,8 @@ // Created by 98max on 1/30/2024. // -#include #include +#include using namespace MaxOS::memory; using namespace MaxOS::system; diff --git a/kernel/src/memory/virtual.cpp b/kernel/src/memory/virtual.cpp new file mode 100644 index 00000000..c9e0728b --- /dev/null +++ b/kernel/src/memory/virtual.cpp @@ -0,0 +1,3 @@ +// +// Created by 98max on 2/11/2024. +// From 3c2da29d80e2159aceb15552dad3a6ca94c7062d Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 2 Mar 2024 19:37:43 +1300 Subject: [PATCH 15/29] Mapping --- README.md | 13 +- kernel/include/memory/physical.h | 50 ++++++- kernel/include/memory/virtual.h | 9 +- kernel/src/asm/loader.s | 120 ++++++++++------- kernel/src/common/kprint.cpp | 13 +- kernel/src/kernel.cpp | 1 + kernel/src/memory/physical.cpp | 225 +++++++++++++++++++++++++++++-- kernel/src/memory/virtual.cpp | 22 +++ kernel/src/system/multiboot.cpp | 16 ++- 9 files changed, 384 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index dafcf347..9fe8b564 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,11 @@ *** for contributors-url, forks-url, etc. This is an optional, concise syntax you may use. *** https://www.markdownguide.org/basic-syntax/#reference-style-links --> -[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] -[![Issues][issues-shield]][issues-url] [![Build][built-shield]][built-url] [![Lines of Code][loc-shield]][loc-url] +[![wakatime][wakatime-shield]][wakatime-url]
@@ -35,7 +34,7 @@

Max OS

- A 32bit hobby operating system written in C++ + A 64bit hobby operating system written in C++
Explore the docs »
@@ -79,7 +78,9 @@ [![MaxOS][product-screenshot]](#) -Max OS is a hobby operating system developed for the 32bit platform using C++ and Assembly. The project is currently in the early stages of development and is not yet ready for use. The project is being developed as a learning experience and is not intended to be used as a production operating system. +!-- CURRENTLY IMPLEMENTING 64BIT SUPPORT, OS IS IN A BROKEN STATE --! + +Max OS is a hobby operating system developed for the 64bit platform using C++ and Assembly. The project is currently in the early stages of development and is not yet ready for use. The project is being developed as a learning experience and is not intended to be used as a production operating system. Max OS supports device drivers, memory management, multitasking, a GUI, and more. The project is being developed with the goal of being able to run on real hardware, however, it is currently only able to run on a virtual machine. @@ -243,4 +244,6 @@ Distributed under the BSD 3-Clause License. See `LICENSE` for more information. [built-shield]: https://img.shields.io/github/actions/workflow/status/maxtyson123/MaxOS/max-os.yml?style=for-the-badge [built-url]: https://github.com/maxtyson123/MaxOS/actions/workflows/max-os.yml [loc-shield]: https://img.shields.io/tokei/lines/github/maxtyson123/MaxOS?style=for-the-badge -[loc-url]: https://github.com/maxtyson123/MaxOS \ No newline at end of file +[loc-url]: https://github.com/maxtyson123/MaxOS +[wakatime-shield]: https://wakatime.com/badge/github/maxtyson123/MaxOS.svg?style=for-the-badge +[wakatime-url]: https://wakatime.com/badge/github/maxtyson123/MaxOS \ No newline at end of file diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index a0031c69..21456102 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -13,10 +13,33 @@ namespace MaxOS { namespace memory { + // Useful for readability + typedef void virtual_address_t; + typedef void physical_address_t; + + typedef enum PageFlags { + None = 0, + Present = (1 << 0), + Write = (1 << 1), + User = (1 << 2), + Address = (1 << 7), + Stack = (1 << 8) + } page_flags_t; + + typedef enum PageBits { + PresentBit = 0b1, + WriteBit = 0b10, + HugePageBit = 0b10000000, + } page_bits_t; + + + // Make a 4KiB Memory Manager? + class PhysicalMemoryManager{ private: - const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB + static const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB + static const uint64_t PAGE_TABLE_OFFSET = { 0xFFFF000000000000 }; // The offset for the page table (before the kernel hihg half) const uint8_t ROW_BITS = { 64 }; uint64_t* m_bit_map; @@ -26,21 +49,40 @@ namespace MaxOS { multiboot_mmap_entry* m_mmap; + uint64_t * m_pml4_root_address; + + uint16_t get_pml4_index(uintptr_t virtual_address); + uint16_t get_page_directory_index(uintptr_t virtual_address); + uint16_t get_page_table_index(uintptr_t virtual_address); + uint16_t get_page_index(uintptr_t virtual_address); + uint64_t get_table_address(uint16_t pml4_index, uint16_t page_directory_index, uint16_t page_table_index, uint16_t page_index); + public: PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot); ~PhysicalMemoryManager(); + // Frame Management void* allocate_frame(); void free_frame(void* address); void* allocate_area(uint64_t start_address, size_t size); void free_area(uint64_t start_address, size_t size); + // Map + virtual_address_t* map(physical_address_t* physical, virtual_address_t* virtual_address, size_t flags); + virtual_address_t* map(virtual_address_t* virtual_address, size_t flags); + void map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags); + void identity_map(physical_address_t* physical_address, size_t flags); + + void unmap(virtual_address_t* virtual_address); + + // Tools - size_t size_to_frames(size_t size) const; - size_t align_to_page(size_t size) const; - bool check_aligned(size_t size) const; + static size_t size_to_frames(size_t size); + static size_t align_to_page(size_t size); + static bool check_aligned(size_t size); + bool is_mapped(uintptr_t physical_address, uintptr_t virtual_address); }; } diff --git a/kernel/include/memory/virtual.h b/kernel/include/memory/virtual.h index 4b8e6eab..37c86156 100644 --- a/kernel/include/memory/virtual.h +++ b/kernel/include/memory/virtual.h @@ -7,21 +7,22 @@ #include #include +#include namespace MaxOS { namespace memory { - // Useful for readability - typedef void virtual_address_t; - typedef void physical_address_t; class VirtualMemoryManager{ private: uint64_t * m_pml4_root_address; + PhysicalMemoryManager* m_physical_memory_manager; + + public: - VirtualMemoryManager(); + VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager); ~VirtualMemoryManager(); }; diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index 32b228f7..b52234f4 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -3,85 +3,114 @@ %define KERNEL_VIRTUAL_ADDR 0xFFFFFFFF80000000 section .multiboot.text global start +global p4_table extern callConstructors extern kernelMain [bits 32] start: - mov edi, ebx ; Address of multiboot structure - mov esi, eax ; Magic number + ; Put the multiboot header and magic number into the parameters of the kernelMain + mov edi, ebx + mov esi, eax + + ; Move the stack to the higher half mov esp, stack.top - KERNEL_VIRTUAL_ADDR - ; For now we are goin to use 2Mib pages - ; We need only 3 table levels instead of 4 - mov eax, p3_table - KERNEL_VIRTUAL_ADDR; Copy p3_table address in eax - or eax, 0b11 ; set writable and present bits to 1 - mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; Copy eax content into the entry 0 of p4 table + ; pm4l -> pdp -> pd -> page + + ; = Configure the first entry in the P4 table to point the the P3 table = + ; * p4_table = pm4l, p3_table = pdp * + ; First we change the address to the higher half + ; Then we set the writable and present bits + ; Then we copy the address into the first entry of the p4_table + mov eax, p3_table - KERNEL_VIRTUAL_ADDR; + or eax, 0b11 + mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax + ; = Configure the the last entry in the P4 table to point the the P3 table = + ; * p4_table = pm4l, p3_table = pdp * + ; First we change the address to the higher half + ; Then we set the writable and present bits + ; Then we copy the address into the last entry of the p4_table mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR or eax, 0b11 mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 511 * 8], eax - mov eax, p2_table - KERNEL_VIRTUAL_ADDR ; Let's do it again, with p2_table - or eax, 0b11 ; Set the writable and present bits - mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; Copy eax content in the 0th entry of p3 + ; = Configure the first entry in the P3 table to point the the P2 table = + ; * p3_table = pdp, p2_table = pd * + ; First we change the address to the higher half + ; Then we set the writable and present bits + ; Then we copy the address into the first entry of the p3_table + mov eax, p2_table - KERNEL_VIRTUAL_ADDR + or eax, 0b11 + mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax + ; = Configure the last entry in the P3 table to point the the P2 table = + ; * p3_table = pdp, p2_table = pd * + ; First we change the address to the higher half + ; Then we set the writable and present bits + ; Then we copy the address into the last entry of the p3_table mov eax, p2_table - KERNEL_VIRTUAL_ADDR or eax, 0b11 mov dword[(p3_table_hh - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax - ; Now let's prepare a loop... - mov ecx, 0 ; Loop counter - + ; = Loop through all the entries in the P2 table and set them to point to a 2MB page = + ; * p2_table = pd * + ; First we set a counter for the loop + ; Then we set the size of the page to 2MB + ; Then we multiply the size of the page by the counter + ; Then we set the huge page bit, writable and present + ; Then we copy the address into the entry in the p2_table + ; After that we increment the counter and check if we have reached the end of the table + mov ecx, 0 .map_p2_table: - mov eax, 0x200000 ; Size of the page - mul ecx ; Multiply by counter - or eax, 0b10000011 ; We set: huge page bit, writable and present - - ; Moving the computed value into p2_table entry defined by ecx * 8 - ; ecx is the counter, 8 is the size of a single entry + mov eax, 0x200000 + mul ecx + or eax, 0b10000011 mov [(p2_table - KERNEL_VIRTUAL_ADDR) + ecx * 8], eax - inc ecx ; Let's increase ecx - cmp ecx, 512 ; have we reached 512 ? - ; each table is 4k size. Each entry is 8bytes - ; that is 512 entries in a table - - jne .map_p2_table ; if ecx < 512 then loop + inc ecx + cmp ecx, 512 + jne .map_p2_table - ; All set... now we are nearly ready to enter into 64 bit - ; Is possible to move into cr3 only from another register - ; So let's move p4_table address into eax first - ; then into cr3 + ; = Load the P4 table into the cr3 register = + ; CR3 is the control register 3, it contains the address of the P4 table, however it can't be loaded directly + ; So we need to load it into eax and then copy it into cr3 mov eax, (p4_table - KERNEL_VIRTUAL_ADDR) mov cr3, eax - ; Now we can enable PAE - ; To do it we need to modify cr4, so first let's copy it into eax - ; we can't modify cr registers directly + ; = Enable PAE (Physical Address Extension) = + ; First we copy the value of cr4 into eax so we can change it + ; Then we set the Physical Address Extension bit + ; Then we copy the value back into cr4 mov eax, cr4 - or eax, 1 << 5 ; Physical address extension bit + or eax, 1 << 5 mov cr4, eax - ; Now set up the long mode bit + ; = Enable Long Mode = + ; First we use the rdmsr instruction to read the value of the msr 0xC0000080 into eax + ; Then we set the Long Mode Enable bit + ; Then we use the wrmsr instruction to write the value of eax into the msr 0xC0000080 mov ecx, 0xC0000080 - ; rdmsr is to read a a model specific register (msr) - ; it copy the values of msr into eax rdmsr or eax, 1 << 8 - ; write back the value wrmsr - ; Now is tiem to enable paging - mov eax, cr0 ;cr0 contains the values we want to change - or eax, 1 << 31 ; Paging bit - or eax, 1 << 16 ; Write protect, cpu can't write to read-only pages when - ; privilege level is 0 - mov cr0, eax ; write back cr0 - - ; load gdt + ; = Enable paging = + ; First we copy the value of cr0 into eax so we can change it + ; Then we set the Paging bit + ; Then we set the Write Protect bit this is to prevent the kernel from writing to read only pages + mov eax, cr0 + or eax, 1 << 31 + or eax, 1 << 16 + mov cr0, eax + + ; = Jump to the higher half = + ; First we load the address of the gdt into the gdtr + ; Then we set the code segment to 0x8 + ; Then we jump to the higher half lgdt [gdt64.pointer_low - KERNEL_VIRTUAL_ADDR] jmp (0x8):(kernel_jumper - KERNEL_VIRTUAL_ADDR) bits 64 @@ -124,7 +153,6 @@ p3_table_hh: resb 4096 p2_table: resb 4096 - stack: resb 16384 .top: diff --git a/kernel/src/common/kprint.cpp b/kernel/src/common/kprint.cpp index 195bd4e0..f3ca9aaa 100644 --- a/kernel/src/common/kprint.cpp +++ b/kernel/src/common/kprint.cpp @@ -14,7 +14,7 @@ using namespace MaxOS::drivers; * @param base The base of the number (10 for decimal, 16 for hex) * @param number The number to convert */ -char* itoa(int base, int number) +char* itoa(int base, uint64_t number) { static char buffer[50] = {0}; int i = 49; @@ -168,21 +168,12 @@ void _kprintf_internal(const char* file, int line, const char* func, const char* case 'x': { // Print a hex - int number = va_arg (parameters, int); + uint64_t number = va_arg (parameters, uint64_t ); char* str = itoa(16, number); for (int i = 0; i < strlen(str); i++) putchar(str[i]); break; } - case 'u': - { - // Print an unsigned decimal - unsigned int number = va_arg (parameters, unsigned int); - char* str = itoa(10, number); - for (int i = 0; i < strlen(str); i++) - putchar(str[i]); - break; - } case 's': { // Print a string diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 7dc207d4..929963b6 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -46,6 +46,7 @@ //MEMORY #include +#include //FILESYSTEM #include diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 74a461cb..3ed67ce3 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -7,25 +7,23 @@ using namespace MaxOS::memory; using namespace MaxOS::system; +extern uint64_t p4_table[]; MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot){ + // SEE boot.s FOR SETUP OF PAGING + // Store the information about the bitmap uint64_t memory_size = (multiboot->get_basic_meminfo() -> mem_upper + 1024) * 1024; - m_bitmap_size = memory_size / PAGE_SIZE; - m_total_entries = m_bitmap_size / ROW_BITS; - - _kprintf("Found Memory with size of %d bytes\n", memory_size); - _kprintf("Bitmap Size: %d\n", m_bitmap_size); - _kprintf("Total Entries: %d \n", m_total_entries); + m_bitmap_size = memory_size / PAGE_SIZE + 1; + m_total_entries = m_bitmap_size / ROW_BITS + 1; // Loop through all the memory map entries multiboot_tag_mmap* mmap = multiboot->get_mmap(); for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { // Skip if the region is not free or there is not enough space - if (entry->type != MULTIBOOT_MEMORY_AVAILABLE || - (entry->addr + entry->len) < reserved) + if (entry->type != MULTIBOOT_MEMORY_AVAILABLE || (entry->addr + entry->len) < reserved) continue; m_mmap = entry; @@ -39,7 +37,7 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Use the memory m_bit_map = (uint64_t *)(m_mmap->addr + offset); - + // Free all the entries for (uint32_t i = 0; i < m_total_entries; ++i) m_bit_map[i] = 0; @@ -56,26 +54,89 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Reserve the area for the bitmap allocate_area((uint64_t)m_bit_map, (m_bitmap_size / 8) + 1); + + // Reserve the area for the mmap + for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + + // Check if the entry is to be mapped + if(entry->type <= 1) + continue; + + allocate_area(entry->addr, entry->len); + } + + // Log where the bitmap starts + _kprintf("Bitmap starts at: 0x%x\n", m_bit_map); + _kprintf("Bitmap size: %d\n", m_bitmap_size); + _kprintf("Bitmap end: 0x%x\n", m_bit_map + m_bitmap_size / 8); + _kprintf("Free memory: %dmb/%dmb (from 0x%x to 0x%x)\n", m_mmap->len / 1024 / 1024, memory_size / 1024 / 1024, m_mmap->addr, m_mmap->addr + m_mmap->len); + + // Set up the PML4 + m_pml4_root_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510,510,510,510)); + + // Mapping information + uintptr_t base_map_address = (uint64_t)MemoryManager::s_higher_half_offset + PAGE_SIZE; //TODO: Maybe PAGE_SIZE should be multiplied by kernel_entries to get the correct padding? + uint64_t physical_address = 0; + uint64_t virtual_address = base_map_address; + + // Check if the paging is working + size_t base_page_entry = get_pml4_index(base_map_address); + if((p4_table[base_page_entry] & 1) == 0) + _kprintf("ERROR: Page Table not set up"); + + // Map all the physical memory into the virtual address space + while(physical_address < memory_size){ + _kprintf("Mapping: 0x%x to 0x%x\n", physical_address, virtual_address); + map((physical_address_t *)physical_address, (virtual_address_t *)virtual_address, Present | Write); + + // Move to the next page + physical_address += PAGE_SIZE; + virtual_address += PAGE_SIZE; + } + + //TODO: Note when the kernel VMM is set up paging should start at base_map_address + memory_size } PhysicalMemoryManager::~PhysicalMemoryManager() { } -size_t PhysicalMemoryManager::size_to_frames(size_t size) const { +uint16_t PhysicalMemoryManager::get_pml4_index(uintptr_t virtual_address) { + // The PML4 index is the last byte + return (uint16_t)((uint64_t)virtual_address >> 39 & 0x1FF); +} + +uint16_t PhysicalMemoryManager::get_page_directory_index(uintptr_t virtual_address) { + // The PDP index is the 3rd byte + return (uint16_t)((uint64_t)virtual_address >> 30 & 0x1FF); +} +uint16_t PhysicalMemoryManager::get_page_table_index(uintptr_t virtual_address) { + // The PD index is the 2nd byte + return (uint16_t)((uint64_t)virtual_address >> 21 & 0x1FF); +} +uint16_t PhysicalMemoryManager::get_page_index(uintptr_t virtual_address) { + // The PT index is the 1st byte (starting from 12) + return (uint16_t)((uint64_t)virtual_address >> 12 & 0x1FF); +} + +uint64_t PhysicalMemoryManager::get_table_address(uint16_t pml4_index, uint16_t pdp_index, uint16_t page_table_index, uint16_t page_index) { + return (pml4_index << 39) | (pdp_index << 30) | (page_table_index << 21) | (page_index << 12); +} + + +size_t PhysicalMemoryManager::size_to_frames(size_t size) { return align_to_page(size) / PAGE_SIZE; } -size_t PhysicalMemoryManager::align_to_page(size_t size) const { +size_t PhysicalMemoryManager::align_to_page(size_t size) { return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); } -bool PhysicalMemoryManager::check_aligned(size_t size) const { +bool PhysicalMemoryManager::check_aligned(size_t size){ return (size % PAGE_SIZE) == 0; } - void* PhysicalMemoryManager::allocate_frame() { // Check if there are enough frames @@ -180,3 +241,141 @@ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { m_bit_map[(frame_address + i) / ROW_BITS] &= ~(1 << ((frame_address + i) % ROW_BITS)); } + +void clean_new_table( uint64_t *table_to_clean ) { + for(int i = 0; i < 512; i++){ + table_to_clean[i] = 0x00l; + } +} + +virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { + + // Check if the address is already mapped + if(is_mapped((uintptr_t)physical, (uintptr_t)virtual_address)) + return virtual_address; + + // Get the indexes of the address + uint16_t pml4_index = get_pml4_index((uintptr_t)virtual_address); + uint16_t page_directory_index = get_page_directory_index((uintptr_t)virtual_address); + uint16_t page_table_index = get_page_table_index((uintptr_t)virtual_address); + + // Get the table address + uint64_t* page_directory_pointer = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, 510 , pml4_index)); + uint64_t* page_directory = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, (uint16_t)pml4_index, (uint16_t)page_directory_index)); + + // Check if the page directory for this address is present + if(!(m_pml4_root_address[pml4_index] & 1)){ + // Allocate a new page directory + uint64_t* new_table = (uint64_t*)allocate_frame(); + m_pml4_root_address[pml4_index] = (uint64_t) new_table | WriteBit | PresentBit; + + // Clear this new address + clean_new_table(page_directory_pointer); + + _kprintf("Allocated new page directory pointer (%d) at: 0x%x, ", pml4_index, &m_pml4_root_address[pml4_index]); + } + + // Check if the page directory for this address is present + if(!(page_directory_pointer[page_directory_index] & 1)){ + + // Allocate a new page table + uint64_t* new_table = (uint64_t*)allocate_frame(); + page_directory_pointer[page_directory_index] = (uint64_t) new_table | WriteBit | PresentBit; + + // The page directory is not present, so we need to clear it + clean_new_table(page_directory); + + _kprintf("Allocated new page directory (%s) at: 0x%x, ", page_directory_index, &page_directory_pointer[page_directory_index]); + } + + // Set the page entry in the page table + page_directory[page_table_index] = (uint64_t) (physical) | HugePageBit | flags; + _kprintf("Mapped: 0x%x to 0x%x\n", (uint64_t)physical, (uint64_t)virtual_address); + return virtual_address; + +} +virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address, size_t flags) { + + // Create a new physical address for the frame + physical_address_t* physical_address = (physical_address_t *)allocate_frame(); + + // Map the physical address to the virtual address + return map(physical_address, virtual_address, flags); + +} + +void PhysicalMemoryManager::map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags) { + + // Get the size of the area + size_t size = size_to_frames(length); + + // Map the required frames + for (size_t i = 0; i < size; ++i) + map(virtual_address_start + (i * PAGE_SIZE), flags); + +} + +void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, size_t flags) { + + // Map the physical address to its virtual address counter-part + map(physical_address, physical_address, flags); + +} + +void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { + + //TODO: TEST WORKS + + // Check if the address is mapped + if(!is_mapped(0, (uintptr_t)virtual_address)) + return; + + // Get the indexes of the address + uint16_t page_directory_pointer = get_pml4_index((uintptr_t)virtual_address); + uint16_t page_directory_index = get_page_directory_index((uintptr_t)virtual_address); + uint16_t page_table_index = get_page_table_index((uintptr_t)virtual_address); + + // Set the page entry in the page directory to 0 + uint64_t* page_directory = (uint64_t*)(PAGE_TABLE_OFFSET | get_table_address(510l, 510, (uint64_t) page_directory_pointer, (uint64_t) page_directory_index)); + page_directory[page_table_index] = 0; + + // Invalidate the TLB + asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); +} + +/** + * @brief Checks if a virtual address is mapped and whether it points to the correct physical address + * @param physical_address The physical address to check (if 0 then wont check if correct entry) + * @param virtual_address The address to check if it is mapped to + * @return True if the physical address is mapped to the virtual address + */ +bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virtual_address) { + + //TODO: Test works + + // Get the indexes of the address + uint16_t pml4_index = get_pml4_index(virtual_address); + uint16_t pdp_index = get_page_directory_index(virtual_address); + uint16_t page_table_index = get_page_table_index(virtual_address); + + // Check if there is a correct entry in the PML4 + if((m_pml4_root_address[pml4_index] & 1) == 0) + return false; + + // Get the address of the pointer to the page directory and check if it is valid + uint64_t* pdp_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, 510 , pdp_index)); + if((pdp_address[pdp_index] & 1) == 0) + return false; + + // Get the address to the page table and check if it is valid + uint64_t* pd_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, page_table_index)); + if((pd_address[page_table_index] & 1) == 0) + return false; + + // If the physical address is a nullpointer then don't bother checking if it is correct + if(physical_address == 0) + return true; + + // Check if the physical address is the same as the one in the page table + return align_to_page((size_t)physical_address) == align_to_page(pd_address[page_table_index]); +} \ No newline at end of file diff --git a/kernel/src/memory/virtual.cpp b/kernel/src/memory/virtual.cpp index c9e0728b..06b5db63 100644 --- a/kernel/src/memory/virtual.cpp +++ b/kernel/src/memory/virtual.cpp @@ -1,3 +1,25 @@ // // Created by 98max on 2/11/2024. // + +#include + +using namespace MaxOS::memory; + +VirtualMemoryManager::VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager) +: m_physical_memory_manager(physical_memory_manager) +{ + + //NOTE: See boot.s for the set up of paging + + // Map the physical memory to the higher half virtual memory + + // TODO: Virtual Memory Management (not just virtual addresses & physical addresses) + +} + +VirtualMemoryManager::~VirtualMemoryManager() { + +} + + diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index 7e24646c..5f50bf85 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -9,7 +9,7 @@ using namespace MaxOS::system; Multiboot::Multiboot(unsigned long addr) { - _kprintf("MUltiboot\n"); + _kprintf("Multiboot\n"); // Loop through the tags and load them struct multiboot_tag *tag; @@ -26,11 +26,23 @@ Multiboot::Multiboot(unsigned long addr) { case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: m_bootloader_name = (multiboot_tag_string *)tag; + _kprintf("Bootloader: %s\n", m_bootloader_name->string); break; + case MULTIBOOT_TAG_TYPE_BOOTDEV: + multiboot_tag_bootdev *bootdev; + bootdev = (multiboot_tag_bootdev *)tag; + _kprintf("Boot device: 0x%x, 0x%x, 0x%x of type 0x%x\n", + (unsigned) bootdev->biosdev, (unsigned) bootdev->slice, + (unsigned) bootdev->part, (unsigned) bootdev->type); + case MULTIBOOT_TAG_TYPE_MMAP: + + // If there is not already a mmap tag, set it + if (m_mmap == nullptr) m_mmap = (multiboot_tag_mmap *)tag; - break; + + break; case MULTIBOOT_TAG_TYPE_ACPI_OLD: m_old_acpi = (multiboot_tag_old_acpi *)tag; From 102ae10efba10222ef71e1f6d588c131744f903b Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Fri, 29 Mar 2024 16:01:28 +1300 Subject: [PATCH 16/29] Mapping (fixed) --- kernel/src/memory/physical.cpp | 58 ++++++++++++++-------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 3ed67ce3..2c261e0f 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -86,7 +86,7 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Map all the physical memory into the virtual address space while(physical_address < memory_size){ - _kprintf("Mapping: 0x%x to 0x%x\n", physical_address, virtual_address); + //_kprintf("Mapping: 0x%x to 0x%x\n", physical_address, virtual_address); map((physical_address_t *)physical_address, (virtual_address_t *)virtual_address, Present | Write); // Move to the next page @@ -250,47 +250,37 @@ void clean_new_table( uint64_t *table_to_clean ) { virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { - // Check if the address is already mapped - if(is_mapped((uintptr_t)physical, (uintptr_t)virtual_address)) - return virtual_address; - // Get the indexes of the address uint16_t pml4_index = get_pml4_index((uintptr_t)virtual_address); - uint16_t page_directory_index = get_page_directory_index((uintptr_t)virtual_address); - uint16_t page_table_index = get_page_table_index((uintptr_t)virtual_address); - - // Get the table address - uint64_t* page_directory_pointer = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, 510 , pml4_index)); - uint64_t* page_directory = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, (uint16_t)pml4_index, (uint16_t)page_directory_index)); - - // Check if the page directory for this address is present - if(!(m_pml4_root_address[pml4_index] & 1)){ - // Allocate a new page directory - uint64_t* new_table = (uint64_t*)allocate_frame(); - m_pml4_root_address[pml4_index] = (uint64_t) new_table | WriteBit | PresentBit; - - // Clear this new address - clean_new_table(page_directory_pointer); - - _kprintf("Allocated new page directory pointer (%d) at: 0x%x, ", pml4_index, &m_pml4_root_address[pml4_index]); + uint16_t pdp_index = get_page_directory_index((uintptr_t)virtual_address); + uint16_t pd_index = get_page_table_index((uintptr_t)virtual_address); + + // Get or create PML4 entry + if ((m_pml4_root_address[pml4_index] & 1) == 0) { + uint64_t* pdp = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, 0)); + m_pml4_root_address[pml4_index] = (uint64_t)pdp | flags; + clean_new_table(pdp); // Clears new page directory pointer table + _kprintf("Created new PML4 entry at index: %d\n", pml4_index); } - // Check if the page directory for this address is present - if(!(page_directory_pointer[page_directory_index] & 1)){ + // Get or create page directory pointer entry + uint64_t* pdp = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, 0)); + if ((pdp[pdp_index] & 1) == 0) { + uint64_t* pd = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, pdp_index, pd_index, 0)); + pdp[pdp_index] = (uint64_t)pd | flags; + clean_new_table(pd); // Clears new page directory table + _kprintf("Created new page directory pointer entry at index: %d\n", pdp_index); + } - // Allocate a new page table - uint64_t* new_table = (uint64_t*)allocate_frame(); - page_directory_pointer[page_directory_index] = (uint64_t) new_table | WriteBit | PresentBit; + // Map the physical address to the virtual address + uint64_t* pd = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, pdp_index, pd_index, 0)); + pd[pd_index] = ((uint64_t)physical & ~(PAGE_SIZE - 1)) | flags; - // The page directory is not present, so we need to clear it - clean_new_table(page_directory); + // Invalidate TLB + asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); - _kprintf("Allocated new page directory (%s) at: 0x%x, ", page_directory_index, &page_directory_pointer[page_directory_index]); - } + _kprintf("Mapped physical address 0x%x to virtual address 0x%x\n", physical, virtual_address); - // Set the page entry in the page table - page_directory[page_table_index] = (uint64_t) (physical) | HugePageBit | flags; - _kprintf("Mapped: 0x%x to 0x%x\n", (uint64_t)physical, (uint64_t)virtual_address); return virtual_address; } From a3714859acce8beb00578c231020805eac23e18e Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Fri, 29 Mar 2024 17:31:09 +1300 Subject: [PATCH 17/29] Mapping (fixed) (clean up) --- kernel/include/memory/physical.h | 33 +++++++++++ kernel/src/memory/physical.cpp | 97 +++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index 21456102..576037e8 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -13,6 +13,13 @@ namespace MaxOS { namespace memory { + + #define PMLX_GET_INDEX(ADDR, LEVEL) (((uint64_t)ADDR & ((uint64_t)0x1ff << (12 + LEVEL * 9))) >> (12 + LEVEL * 9)) + + #define PML4_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 3) + #define PML3_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 2) + #define PML2_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 1) + // Useful for readability typedef void virtual_address_t; typedef void physical_address_t; @@ -32,6 +39,26 @@ namespace MaxOS { HugePageBit = 0b10000000, } page_bits_t; + // Struct for a page table entry + typedef struct PageTableEntry { + uint64_t present : 1; + uint64_t write : 1; + uint64_t user : 1; + uint64_t write_through : 1; + uint64_t cache_disabled : 1; + uint64_t accessed : 1; + uint64_t dirty : 1; + uint64_t huge_page : 1; + uint64_t global : 1; + uint64_t available : 3; + uint64_t physical_address : 40; + } __attribute__((packed)) pte_t; + + // Struct for a page map level + typedef struct PageMapLevel { + pte_t entries[512]; + } __attribute__((packed)) pml_t; + // Make a 4KiB Memory Manager? @@ -57,6 +84,12 @@ namespace MaxOS { uint16_t get_page_index(uintptr_t virtual_address); uint64_t get_table_address(uint16_t pml4_index, uint16_t page_directory_index, uint16_t page_table_index, uint16_t page_index); + + void clean_page_table(uint64_t* table); + + pml_t* get_or_create_table(pml_t* table, size_t index, size_t flags); + pte_t create_page_table_entry(uintptr_t address, size_t flags); + public: PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot); diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 2c261e0f..68725ef1 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -242,48 +242,58 @@ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { } -void clean_new_table( uint64_t *table_to_clean ) { - for(int i = 0; i < 512; i++){ - table_to_clean[i] = 0x00l; - } +pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, size_t flags) { + + // Get the entry from the table + pte_t entry = table->entries[index]; + + // Check if the entry is present + if(entry.present) { + + // Get the address of the table + return (pml_t*)(entry.physical_address << 12); + + } + + _kprintf("Creating new table at index: %d\n", index); + + // Need to create a new table + pml_t* new_table = (pml_t*)allocate_frame(); + + // Clean the table + clean_page_table((uint64_t*)new_table); + + // Set the entry + table->entries[index] = create_page_table_entry((uintptr_t)new_table, flags); + + return new_table; + + } + virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { - // Get the indexes of the address - uint16_t pml4_index = get_pml4_index((uintptr_t)virtual_address); - uint16_t pdp_index = get_page_directory_index((uintptr_t)virtual_address); - uint16_t pd_index = get_page_table_index((uintptr_t)virtual_address); - - // Get or create PML4 entry - if ((m_pml4_root_address[pml4_index] & 1) == 0) { - uint64_t* pdp = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, 0)); - m_pml4_root_address[pml4_index] = (uint64_t)pdp | flags; - clean_new_table(pdp); // Clears new page directory pointer table - _kprintf("Created new PML4 entry at index: %d\n", pml4_index); - } + // Get the page directory pointer m_pml4_root_address + pml_t* pml3 = get_or_create_table((pml_t*)m_pml4_root_address, PML4_GET_INDEX(virtual_address), (flags | WriteBit)); - // Get or create page directory pointer entry - uint64_t* pdp = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, 0)); - if ((pdp[pdp_index] & 1) == 0) { - uint64_t* pd = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, pdp_index, pd_index, 0)); - pdp[pdp_index] = (uint64_t)pd | flags; - clean_new_table(pd); // Clears new page directory table - _kprintf("Created new page directory pointer entry at index: %d\n", pdp_index); - } + // Get the page directory + pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); - // Map the physical address to the virtual address - uint64_t* pd = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, pdp_index, pd_index, 0)); - pd[pd_index] = ((uint64_t)physical & ~(PAGE_SIZE - 1)) | flags; + // Get the entry + pte_t* pte = &pml2->entries[PML2_GET_INDEX(virtual_address)]; - // Invalidate TLB - asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); + // Check if already mapped + if(pte->present) + return virtual_address; - _kprintf("Mapped physical address 0x%x to virtual address 0x%x\n", physical, virtual_address); + // Set the entry + *pte = create_page_table_entry((uintptr_t)physical, flags); - return virtual_address; + _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); } + virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address, size_t flags) { // Create a new physical address for the frame @@ -368,4 +378,27 @@ bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virt // Check if the physical address is the same as the one in the page table return align_to_page((size_t)physical_address) == align_to_page(pd_address[page_table_index]); -} \ No newline at end of file +} + + +void PhysicalMemoryManager::clean_page_table(uint64_t *table) { + for(int i = 0; i < 512; i++){ + table[i] = 0x00l; + } +} +pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) { + + return (pte_t){ + .present = 1, + .write = flags & Write, + .user = flags & User, + .write_through = (flags & (1 << 7)) != 0, + .accessed = 0, + .dirty = 0, + .huge_page = 0, + .global = 0, + .available = 0, + .physical_address = (uint64_t)address >> 12 + }; + +} From 7c596d126068bb0ace182216b0f3075f17f99e85 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 30 Mar 2024 12:51:52 +1300 Subject: [PATCH 18/29] Root Address from asm --- kernel/include/hardwarecommunication/apic.h | 2 ++ kernel/include/memory/physical.h | 8 ++++++-- kernel/src/hardwarecommunication/apic.cpp | 7 +++++++ kernel/src/kernel.cpp | 5 +++-- kernel/src/memory/physical.cpp | 22 +++++++++------------ toolchain/run_qemu.sh | 4 ++-- 6 files changed, 29 insertions(+), 19 deletions(-) diff --git a/kernel/include/hardwarecommunication/apic.h b/kernel/include/hardwarecommunication/apic.h index fd69c938..17adda6c 100644 --- a/kernel/include/hardwarecommunication/apic.h +++ b/kernel/include/hardwarecommunication/apic.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace MaxOS { namespace hardwarecommunication { @@ -17,6 +18,7 @@ namespace MaxOS { protected: uint64_t m_apic_base; + uint64_t m_apic_base_high; uint32_t m_id; bool m_x2apic; diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index 576037e8..a4a8dabf 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -13,6 +13,7 @@ namespace MaxOS { namespace memory { + #define VirtualPointer(addr) (void*)((uint64_t)(addr)) #define PMLX_GET_INDEX(ADDR, LEVEL) (((uint64_t)ADDR & ((uint64_t)0x1ff << (12 + LEVEL * 9))) >> (12 + LEVEL * 9)) @@ -76,7 +77,8 @@ namespace MaxOS { multiboot_mmap_entry* m_mmap; - uint64_t * m_pml4_root_address; + uint64_t* m_pml4_root_address; + pte_t* m_pml4_root; uint16_t get_pml4_index(uintptr_t virtual_address); uint16_t get_page_directory_index(uintptr_t virtual_address); @@ -92,7 +94,7 @@ namespace MaxOS { public: - PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot); + PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot, uint64_t pml4_root[512]); ~PhysicalMemoryManager(); // Frame Management @@ -116,6 +118,8 @@ namespace MaxOS { static size_t align_to_page(size_t size); static bool check_aligned(size_t size); bool is_mapped(uintptr_t physical_address, uintptr_t virtual_address); + + static PhysicalMemoryManager* current_manager; }; } diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index 834d91ef..c41e89a1 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -7,6 +7,7 @@ using namespace MaxOS; using namespace MaxOS::hardwarecommunication; using namespace MaxOS::system; +using namespace MaxOS::memory; LocalAPIC::LocalAPIC() { @@ -41,6 +42,12 @@ void LocalAPIC::init() { m_x2apic = false; _kprintf("CPU supports xAPIC\n"); + // Map the APIC base address to the higher half + m_apic_base_high = MemoryManager::s_higher_half_offset + 0x12000; + PhysicalMemoryManager::current_manager->map(VirtualPointer(m_apic_base), VirtualPointer(m_apic_base_high), Present | Write); + _kprintf("APIC Base: 0x%x\n", m_apic_base); + _kprintf("APIC Higher Half: 0x%x\n", m_apic_base_high); + } else { _kprintf("ERROR: CPU does not support APIC (BAD!!)\n"); } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 929963b6..93d3e4a0 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -106,7 +106,7 @@ void print_boot_header(Console* console){ } -extern uint32_t kernel_end; +extern uint64_t p4_table[512]; extern "C" void kernelMain(unsigned long addr, unsigned long magic) { @@ -125,8 +125,9 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("IDT set up\n"); uint32_t mbi_size = *(uint32_t *) (addr + MemoryManager::s_higher_half_offset); - PhysicalMemoryManager pmm(addr + mbi_size, &multiboot); + PhysicalMemoryManager pmm(addr + mbi_size, &multiboot, p4_table); _kprintf("Physical Memory Manager set up \n"); + _kprintf("Verify Page Root Address: 0x%x\n", &p4_table); AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("ACPI set up\n"); diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 68725ef1..788b33b3 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -9,9 +9,16 @@ using namespace MaxOS::memory; using namespace MaxOS::system; extern uint64_t p4_table[]; -MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot){ +PhysicalMemoryManager* PhysicalMemoryManager::current_manager = nullptr; + +MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot, uint64_t pml4_root[512]){ // SEE boot.s FOR SETUP OF PAGING + m_pml4_root = (pte_t*)pml4_root; + m_pml4_root_address = pml4_root; + + // Set the current manager + current_manager = this; // Store the information about the bitmap uint64_t memory_size = (multiboot->get_basic_meminfo() -> mem_upper + 1024) * 1024; @@ -71,8 +78,6 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv _kprintf("Bitmap end: 0x%x\n", m_bit_map + m_bitmap_size / 8); _kprintf("Free memory: %dmb/%dmb (from 0x%x to 0x%x)\n", m_mmap->len / 1024 / 1024, memory_size / 1024 / 1024, m_mmap->addr, m_mmap->addr + m_mmap->len); - // Set up the PML4 - m_pml4_root_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510,510,510,510)); // Mapping information uintptr_t base_map_address = (uint64_t)MemoryManager::s_higher_half_offset + PAGE_SIZE; //TODO: Maybe PAGE_SIZE should be multiplied by kernel_entries to get the correct padding? @@ -84,17 +89,8 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv if((p4_table[base_page_entry] & 1) == 0) _kprintf("ERROR: Page Table not set up"); - // Map all the physical memory into the virtual address space - while(physical_address < memory_size){ - //_kprintf("Mapping: 0x%x to 0x%x\n", physical_address, virtual_address); - map((physical_address_t *)physical_address, (virtual_address_t *)virtual_address, Present | Write); - - // Move to the next page - physical_address += PAGE_SIZE; - virtual_address += PAGE_SIZE; - } - //TODO: Note when the kernel VMM is set up paging should start at base_map_address + memory_size + _kprintf("_Test Page Root Address: 0x%x\n", m_pml4_root_address); } PhysicalMemoryManager::~PhysicalMemoryManager() { diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh index 6b394de4..a75d88b9 100755 --- a/toolchain/run_qemu.sh +++ b/toolchain/run_qemu.sh @@ -136,9 +136,9 @@ fi # Create the args QEMU_ARGS="" -QEMU_ARGS="$QEMU_ARGS -m 2G" # 512 MB of RAM +QEMU_ARGS="$QEMU_ARGS -m 2G" # 2 GB of RAM QEMU_ARGS="$QEMU_ARGS -smp cores=4" # 4 cores -QEMU_ARGS="$QEMU_ARGS -serial stdio" # Use stdio for serial +QEMU_ARGS="$QEMU_ARGS -monitor stdio" # Use stdio for serial if [ ! "$USE_DEBUG" -ne "0" ]; then QEMU_ARGS="$QEMU_ARGS -d int" # Debug interrupts fi From f020018ea04c2f746beaef632f7e4a628b5b0496 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 30 Mar 2024 16:33:19 +1300 Subject: [PATCH 19/29] Paging Test Fixes --- kernel/include/memory/memorymanagement.h | 6 ++++-- kernel/include/memory/physical.h | 8 ++------ kernel/src/hardwarecommunication/apic.cpp | 6 +++--- kernel/src/kernel.cpp | 2 +- kernel/src/memory/memorymanagement.cpp | 16 +++++++++++++++- kernel/src/memory/physical.cpp | 11 ++++++----- toolchain/run_qemu.sh | 2 +- 7 files changed, 32 insertions(+), 19 deletions(-) diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index ffc0a2c9..a205abda 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -38,7 +38,8 @@ namespace MaxOS{ public: static MemoryManager* s_active_memory_manager; - static const uint64_t s_higher_half_offset { 0xFFFFFFFF80000000 }; + static const uint64_t s_higher_half_offset { 0xFFFFFFFF80000000 }; + static const uint64_t s_mem_io_offset { s_higher_half_offset - 0x100000000}; MemoryManager(multiboot_tag_mmap* memory_map); ~MemoryManager(); @@ -47,7 +48,8 @@ namespace MaxOS{ void free(void* pointer); int memory_used(); - static uint64_t map_to_higher_half(uint64_t physical_address); + static uint64_t to_higher_region(uint64_t physical_address); + static uint64_t to_io_region(uint64_t physical_address); }; } } diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index a4a8dabf..bdc32841 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -35,9 +35,8 @@ namespace MaxOS { } page_flags_t; typedef enum PageBits { - PresentBit = 0b1, - WriteBit = 0b10, - HugePageBit = 0b10000000, + WriteBit = (1 << 1), + UserBit = (1 << 3), } page_bits_t; // Struct for a page table entry @@ -60,9 +59,6 @@ namespace MaxOS { pte_t entries[512]; } __attribute__((packed)) pml_t; - - // Make a 4KiB Memory Manager? - class PhysicalMemoryManager{ private: diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index c41e89a1..71ce16bf 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -43,7 +43,7 @@ void LocalAPIC::init() { _kprintf("CPU supports xAPIC\n"); // Map the APIC base address to the higher half - m_apic_base_high = MemoryManager::s_higher_half_offset + 0x12000; + m_apic_base_high = MemoryManager::to_io_region(m_apic_base); PhysicalMemoryManager::current_manager->map(VirtualPointer(m_apic_base), VirtualPointer(m_apic_base_high), Present | Write); _kprintf("APIC Base: 0x%x\n", m_apic_base); _kprintf("APIC Higher Half: 0x%x\n", m_apic_base_high); @@ -73,7 +73,7 @@ uint32_t LocalAPIC::read(uint32_t reg) { if(m_x2apic) { return (uint32_t)CPU::read_msr((reg >> 4) + 0x800); } else { - return (*(volatile uint32_t*)((uintptr_t)m_apic_base + reg)); + return (*(volatile uint32_t*)((uintptr_t)m_apic_base_high + reg)); } } @@ -84,7 +84,7 @@ void LocalAPIC::write(uint32_t reg, uint32_t value) { if(m_x2apic) { CPU::write_msr((reg >> 4) + 0x800, value); } else { - (*(volatile uint32_t*)((uintptr_t)m_apic_base + reg)) = value; + (*(volatile uint32_t*)((uintptr_t)m_apic_base_high + reg)) = value; } } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 93d3e4a0..c2e61be3 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -106,7 +106,7 @@ void print_boot_header(Console* console){ } -extern uint64_t p4_table[512]; +extern volatile uint64_t p4_table[512]; extern "C" void kernelMain(unsigned long addr, unsigned long magic) { diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index 3b1fbf0f..ac1aae47 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -157,7 +157,7 @@ int MemoryManager::memory_used() { return result; } -uint64_t MemoryManager::map_to_higher_half(uint64_t physical_address) { +uint64_t MemoryManager::to_higher_region(uint64_t physical_address) { // Check if the address is already mapped if(physical_address >= s_higher_half_offset) @@ -167,6 +167,20 @@ uint64_t MemoryManager::map_to_higher_half(uint64_t physical_address) { return physical_address + s_higher_half_offset; } +uint64_t MemoryManager::to_io_region(uint64_t physical_address) { + + // Check if the address is already mapped + if(physical_address >= s_mem_io_offset) + return physical_address; + + // Check if the address is past 4GB + if(physical_address >= 0xFFFFFFFF) + return physical_address; + + // Map the address to the higher half + return physical_address + s_mem_io_offset; +} + //Redefine the default object functions with memory orientated ones (defaults disabled in makefile) diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 788b33b3..cbae3555 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -82,17 +82,15 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Mapping information uintptr_t base_map_address = (uint64_t)MemoryManager::s_higher_half_offset + PAGE_SIZE; //TODO: Maybe PAGE_SIZE should be multiplied by kernel_entries to get the correct padding? uint64_t physical_address = 0; - uint64_t virtual_address = base_map_address; // Check if the paging is working size_t base_page_entry = get_pml4_index(base_map_address); if((p4_table[base_page_entry] & 1) == 0) _kprintf("ERROR: Page Table not set up"); - //TODO: Note when the kernel VMM is set up paging should start at base_map_address + memory_size - _kprintf("_Test Page Root Address: 0x%x\n", m_pml4_root_address); } + PhysicalMemoryManager::~PhysicalMemoryManager() { } @@ -286,6 +284,9 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt // Set the entry *pte = create_page_table_entry((uintptr_t)physical, flags); + // Invalidate the TLB + asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); + _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); } @@ -386,8 +387,8 @@ pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t f return (pte_t){ .present = 1, - .write = flags & Write, - .user = flags & User, + .write = (flags & WriteBit) != 0, + .user = (flags & UserBit) != 0, .write_through = (flags & (1 << 7)) != 0, .accessed = 0, .dirty = 0, diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh index a75d88b9..2e9d4669 100755 --- a/toolchain/run_qemu.sh +++ b/toolchain/run_qemu.sh @@ -138,7 +138,7 @@ fi QEMU_ARGS="" QEMU_ARGS="$QEMU_ARGS -m 2G" # 2 GB of RAM QEMU_ARGS="$QEMU_ARGS -smp cores=4" # 4 cores -QEMU_ARGS="$QEMU_ARGS -monitor stdio" # Use stdio for serial +QEMU_ARGS="$QEMU_ARGS -serial stdio" # Use stdio for serial if [ ! "$USE_DEBUG" -ne "0" ]; then QEMU_ARGS="$QEMU_ARGS -d int" # Debug interrupts fi From 39945bc3979b9431ff2a0521d1ce33c88fd8daa6 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 30 Mar 2024 17:12:29 +1300 Subject: [PATCH 20/29] Missing Huge Page Bit --- kernel/include/common/kprint.h | 9 ++- kernel/src/common/kprint.cpp | 86 ++++++++++++++--------- kernel/src/hardwarecommunication/acpi.cpp | 13 ++-- kernel/src/hardwarecommunication/apic.cpp | 7 +- kernel/src/memory/physical.cpp | 6 +- 5 files changed, 70 insertions(+), 51 deletions(-) diff --git a/kernel/include/common/kprint.h b/kernel/include/common/kprint.h index 15808e85..52bd047a 100644 --- a/kernel/include/common/kprint.h +++ b/kernel/include/common/kprint.h @@ -10,9 +10,14 @@ #define _kprintf(format, ...) \ - _kprintf_internal(__FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) + _kprintf_internal(0, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__) +#define ASSERT(condition, format, ...) \ + if(!(condition)) { \ + _kprintf_internal(3, __FILE__, __LINE__, __FUNCTION__, format, ##__VA_ARGS__); \ + while(1); \ + } -void _kprintf_internal(const char* file, int line, const char* func, const char* format, ...); +void _kprintf_internal(uint8_t type, const char* file, int line, const char* func, const char* format, ...); #endif // MAXOS_KPRINT_H diff --git a/kernel/src/common/kprint.cpp b/kernel/src/common/kprint.cpp index f3ca9aaa..6801d89e 100644 --- a/kernel/src/common/kprint.cpp +++ b/kernel/src/common/kprint.cpp @@ -74,42 +74,64 @@ static void putchar (int c) /** * @ brief Prints a debug prefix (in yellow) to the serial output */ -void pre_kprintf(const char* file, int line, const char* func) +void pre_kprintf(const char* file, int line, const char* func, uint8_t type) { - // Print the kernel header with yellow text - const char* header = "\033[1;33m["; - for (int i = 0; i < strlen(header); i++) - putchar(header[i]); - - // Print the file (but not the path) - const char* file_str = file; - for (int i = strlen(file) - 1; i >= 0; i--) - { - if (file[i] == '/') - { - file_str = &file[i + 1]; + + // Print the colour + char* colour = "---------"; + switch (type) { + + // Log (yellow) + case 0: + colour = "\033[1;33m"; break; - } - }\ - for (int j = 0; j < strlen(file_str); j++) - putchar(file_str[j]); - putchar(':'); + // Assert (red) + case 3: + colour = "\033[1;31m"; + break; + } + + for (int i = 0; i < strlen(colour); i++) + putchar(colour[i]); + + putchar('['); - // Print the line - const char* line_str = itoa(10, line); - for (int i = 0; i < strlen(line_str); i++) - putchar(line_str[i]); + // File Output + if(type == 0){ - /* Print the spacer - putchar(' '); - putchar('-'); - putchar(' '); + // Print the file (but not the path) + const char* file_str = file; + for (int i = strlen(file) - 1; i >= 0; i--) + { + if (file[i] == '/') + { + file_str = &file[i + 1]; + break; + } + }\ + for (int j = 0; j < strlen(file_str); j++) + putchar(file_str[j]); + putchar(':'); + + // Print the line + const char* line_str = itoa(10, line); + for (int i = 0; i < strlen(line_str); i++) + putchar(line_str[i]); + }else{ + + // Print the text + const char* text = "FATAL ERROR IN {"; + for (int i = 0; i < strlen(text); i++) + putchar(text[i]); + + // Print the function + for (int i = 0; i < strlen(func); i++) + putchar(func[i]); + + putchar('}'); + } - // Print the function - for (int i = 0; i < strlen(func); i++) - putchar(func[i]); - */ // Print the kernel footer const char* footer = "] \033[0m"; @@ -130,11 +152,11 @@ void pre_kprintf(const char* file, int line, const char* func) * @param format The formatted string * @param ... The data to pass into the string */ -void _kprintf_internal(const char* file, int line, const char* func, const char* format, ...) +void _kprintf_internal(uint8_t type, const char* file, int line, const char* func, const char* format, ...) { // Print the header - pre_kprintf(file, line,func); + pre_kprintf(file, line,func, type); // Create a pointer to the data va_list parameters; diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index af6a2ad5..da9a3c85 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -25,18 +25,14 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s sum += ((char*)rsdp)[i]; // Check if the checksum is valid - if(sum != 0) - _kprintf("ACPI: Invalid checksum!\n"); + ASSERT(sum == 0, "Invalid checksum!") }else{ // If the new ACPI is not supported, panic - if(multiboot->get_new_acpi() == 0){ - _kprintf("ACPI: No ACPI found! (BAD)\n"); - return; - } + ASSERT(multiboot->get_new_acpi() != 0, "No ACPI found!") - // Its the new ACPI + // It's the new ACPI m_type = 1; // Get the RSDP & XSDT @@ -52,8 +48,7 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s sum += ((char*)rsdp2)[i]; // Check if the checksum is valid - if(sum != 0) - _kprintf("ACPI: Invalid checksum!\n"); + ASSERT(sum == 0, "Invalid checksum!") } } diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index 71ce16bf..18e8beb3 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -49,7 +49,7 @@ void LocalAPIC::init() { _kprintf("APIC Higher Half: 0x%x\n", m_apic_base_high); } else { - _kprintf("ERROR: CPU does not support APIC (BAD!!)\n"); + ASSERT(false, "CPU does not support xAPIC") } // Get the vector table @@ -116,10 +116,7 @@ void IOAPIC::init() { MADT_Item* io_apic_item = get_madt_item(1, 0); // Check if the IO APIC was found - if(io_apic_item == nullptr) { - _kprintf("ERROR: IO APIC not found\n"); - return; - } + ASSERT(io_apic_item == nullptr, "IO APIC not found") // Get the IO APIC address MADT_IOAPIC* io_apic = (MADT_IOAPIC*)io_apic_item; diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index cbae3555..8a273382 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -85,8 +85,8 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Check if the paging is working size_t base_page_entry = get_pml4_index(base_map_address); - if((p4_table[base_page_entry] & 1) == 0) - _kprintf("ERROR: Page Table not set up"); + + ASSERT(((p4_table[base_page_entry] & 1) != 0), "Page Table not set up"); } @@ -392,7 +392,7 @@ pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t f .write_through = (flags & (1 << 7)) != 0, .accessed = 0, .dirty = 0, - .huge_page = 0, + .huge_page = 1, .global = 0, .available = 0, .physical_address = (uint64_t)address >> 12 From 67669e1756dff3b7ceff8952605aaed7d5b53bb1 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Wed, 3 Apr 2024 21:46:25 +1300 Subject: [PATCH 21/29] LAPIC Mapping works --- kernel/include/hardwarecommunication/acpi.h | 1 + kernel/include/hardwarecommunication/apic.h | 1 + kernel/include/memory/physical.h | 30 ++++++--- kernel/src/hardwarecommunication/acpi.cpp | 5 ++ kernel/src/hardwarecommunication/apic.cpp | 18 +++-- .../src/hardwarecommunication/interrupts.cpp | 2 + kernel/src/kernel.cpp | 5 ++ kernel/src/memory/physical.cpp | 66 +++++++++++++++---- 8 files changed, 98 insertions(+), 30 deletions(-) diff --git a/kernel/include/hardwarecommunication/acpi.h b/kernel/include/hardwarecommunication/acpi.h index f878283c..e3a88e16 100644 --- a/kernel/include/hardwarecommunication/acpi.h +++ b/kernel/include/hardwarecommunication/acpi.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace MaxOS { namespace hardwarecommunication { diff --git a/kernel/include/hardwarecommunication/apic.h b/kernel/include/hardwarecommunication/apic.h index 17adda6c..0f3c31a5 100644 --- a/kernel/include/hardwarecommunication/apic.h +++ b/kernel/include/hardwarecommunication/apic.h @@ -82,6 +82,7 @@ namespace MaxOS { AdvancedConfigurationAndPowerInterface* m_acpi; MADT* m_madt; uint32_t m_address; + uint64_t m_address_high; uint32_t m_version; uint8_t m_max_redirect_entry; diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index bdc32841..862014fb 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -26,17 +26,23 @@ namespace MaxOS { typedef void physical_address_t; typedef enum PageFlags { - None = 0, - Present = (1 << 0), - Write = (1 << 1), - User = (1 << 2), - Address = (1 << 7), - Stack = (1 << 8) + None = 0, + Present = (1 << 0), + Write = (1 << 1), + User = (1 << 2), + WriteThrough = (1 << 3), + CacheDisabled = (1 << 4), + Accessed = (1 << 5), + Dirty = (1 << 6), + HugePage = (1 << 7), + Global = (1 << 8) + } page_flags_t; typedef enum PageBits { WriteBit = (1 << 1), UserBit = (1 << 3), + HugePageBit = (1 << 7), } page_bits_t; // Struct for a page table entry @@ -51,7 +57,7 @@ namespace MaxOS { uint64_t huge_page : 1; uint64_t global : 1; uint64_t available : 3; - uint64_t physical_address : 40; + uint64_t physical_address : 52; } __attribute__((packed)) pte_t; // Struct for a page map level @@ -62,8 +68,6 @@ namespace MaxOS { class PhysicalMemoryManager{ private: - static const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB - static const uint64_t PAGE_TABLE_OFFSET = { 0xFFFF000000000000 }; // The offset for the page table (before the kernel hihg half) const uint8_t ROW_BITS = { 64 }; uint64_t* m_bit_map; @@ -93,6 +97,11 @@ namespace MaxOS { PhysicalMemoryManager(unsigned long reserved, system::Multiboot* multiboot, uint64_t pml4_root[512]); ~PhysicalMemoryManager(); + + // Vars + static const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB + static const uint64_t PAGE_TABLE_OFFSET = { 0xFFFF000000000000 }; // The offset for the page table (before the kernel hihg half) + // Frame Management void* allocate_frame(); void free_frame(void* address); @@ -101,9 +110,10 @@ namespace MaxOS { void free_area(uint64_t start_address, size_t size); // Map - virtual_address_t* map(physical_address_t* physical, virtual_address_t* virtual_address, size_t flags); virtual_address_t* map(virtual_address_t* virtual_address, size_t flags); + virtual_address_t* map(physical_address_t* physical, virtual_address_t* virtual_address, size_t flags); void map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags); + void map_area(physical_address_t* physical_address_start, virtual_address_t* virtual_address_start, size_t length, size_t flags); void identity_map(physical_address_t* physical_address, size_t flags); void unmap(virtual_address_t* virtual_address); diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index da9a3c85..f037c77d 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -16,8 +16,13 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s RSDPDescriptor* rsdp = (RSDPDescriptor*)(multiboot->get_old_acpi() + 1); m_rsdt = (RSDT*) rsdp->rsdt_address; + // Map the RSDT + PhysicalMemoryManager::current_manager->map(VirtualPointer(m_rsdt), VirtualPointer(MemoryManager::to_higher_region((uint64_t)m_rsdt)), PageFlags::Write); + m_rsdt = (RSDT*) MemoryManager::to_higher_region((uint64_t)m_rsdt); + // Load the header m_header = &m_rsdt->header; + ASSERT(m_header->length > PhysicalMemoryManager::PAGE_SIZE, "RSDT needs more pages!") // Calculate the checksum uint8_t sum = 0; diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index 18e8beb3..1d57181d 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -44,7 +44,7 @@ void LocalAPIC::init() { // Map the APIC base address to the higher half m_apic_base_high = MemoryManager::to_io_region(m_apic_base); - PhysicalMemoryManager::current_manager->map(VirtualPointer(m_apic_base), VirtualPointer(m_apic_base_high), Present | Write); + PhysicalMemoryManager::current_manager->map(VirtualPointer(m_apic_base), VirtualPointer(m_apic_base_high), Write); _kprintf("APIC Base: 0x%x\n", m_apic_base); _kprintf("APIC Higher Half: 0x%x\n", m_apic_base_high); @@ -64,7 +64,6 @@ void LocalAPIC::init() { uint32_t version = read(0x30); _kprintf("APIC Version: 0x%x\n", version & 0xFF); - } uint32_t LocalAPIC::read(uint32_t reg) { @@ -122,6 +121,13 @@ void IOAPIC::init() { MADT_IOAPIC* io_apic = (MADT_IOAPIC*)io_apic_item; m_address = io_apic->io_apic_address; + // Map the IO APIC address to the higher half + m_address_high = MemoryManager::to_io_region(m_address); + PhysicalMemoryManager::current_manager->map(VirtualPointer(m_address), VirtualPointer(m_address_high), Write); + + _kprintf("IO APIC Address: 0x%x\n", m_address); + _kprintf("IO APIC Higher Half: 0x%x\n", m_address_high); + // Get the IO APIC version and max redirection entry m_version = read(0x01); m_max_redirect_entry = (uint8_t)(m_version >> 16); @@ -203,10 +209,10 @@ MADT_Item *IOAPIC::get_madt_item(uint8_t type, uint8_t index) { uint32_t IOAPIC::read(uint32_t reg) { // Write the register - *(volatile uint32_t*)(m_address + 0x00) = reg; + *(volatile uint32_t*)(m_address_high + 0x00) = reg; // Return the value - return *(volatile uint32_t*)(m_address + 0x10); + return *(volatile uint32_t*)(m_address_high + 0x10); } @@ -214,10 +220,10 @@ uint32_t IOAPIC::read(uint32_t reg) { void IOAPIC::write(uint32_t reg, uint32_t value) { // Write the register - *(volatile uint32_t*)(m_address + 0x00) = reg; + *(volatile uint32_t*)(m_address_high + 0x00) = reg; // Write the value - *(volatile uint32_t*)(m_address + 0x10) = value; + *(volatile uint32_t*)(m_address_high + 0x10) = value; } void IOAPIC::read_redirect(uint8_t index, RedirectionEntry *entry) { diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index ce00ab6a..e334b767 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -182,6 +182,8 @@ void InterruptManager::deactivate() */ system::cpu_status_t* InterruptManager::HandleInterrupt(system::cpu_status_t *status) { + ASSERT(false, "Interupt number 0x%x, Code: 0x%x", status->interrupt_number, status->error_code); + // If there is an interrupt manager handle interrupt if(s_active_interrupt_manager != 0) return s_active_interrupt_manager->handle_interrupt_request(status); diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index c2e61be3..9b0aa6ed 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -139,6 +139,11 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("IDT activated\n"); // TODO: 64 bit architecture rewrite + // - Fix Paging + // - Finish ACPI + // - Memory Allocation + // - Convert old codebase + _kprintf("KERNEL DONE\n"); while (true) { //TODO: This causes a Double Fault and then infinte General Protection Faults system::CPU::halt(); diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 8a273382..0b5add71 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -78,15 +78,35 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv _kprintf("Bitmap end: 0x%x\n", m_bit_map + m_bitmap_size / 8); _kprintf("Free memory: %dmb/%dmb (from 0x%x to 0x%x)\n", m_mmap->len / 1024 / 1024, memory_size / 1024 / 1024, m_mmap->addr, m_mmap->addr + m_mmap->len); + return; - // Mapping information - uintptr_t base_map_address = (uint64_t)MemoryManager::s_higher_half_offset + PAGE_SIZE; //TODO: Maybe PAGE_SIZE should be multiplied by kernel_entries to get the correct padding? - uint64_t physical_address = 0; + // Allocate a new PML4 root + m_pml4_root_address = (uint64_t*)allocate_frame(); + m_pml4_root = (pte_t*)m_pml4_root_address; - // Check if the paging is working - size_t base_page_entry = get_pml4_index(base_map_address); + // Map the first two pages for the kernel + map_area((physical_address_t*)0, (virtual_address_t*)MemoryManager::s_higher_half_offset, PAGE_SIZE * 2, Present); - ASSERT(((p4_table[base_page_entry] & 1) != 0), "Page Table not set up"); + // Map 4 GB of physical memory + _kprintf("Mapping 4Gb Of io region...\n"); + map_area((physical_address_t*)0, (virtual_address_t*)MemoryManager::s_active_memory_manager -> to_io_region(0), 0xFFFFFFFF, Write); + + // Re-map the mmap + for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + + // Check this + + // 4GB Already mapped + if(entry->addr >= 0xFFFFFFFF) + continue; + + _kprintf("Mapping (io) mmap 0x%x - 0x%x\n", entry->addr, entry -> addr + entry->len); + map_area((physical_address_t*)entry->addr, (virtual_address_t *)MemoryManager::s_active_memory_manager -> to_io_region(entry->addr), entry -> len, Write); + } + + + // Load the new PML4 + asm volatile("mov %0, %%cr3" :: "r"(m_pml4_root_address)); } @@ -275,6 +295,7 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the entry + uint64_t index = PML2_GET_INDEX(virtual_address); pte_t* pte = &pml2->entries[PML2_GET_INDEX(virtual_address)]; // Check if already mapped @@ -282,10 +303,7 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt return virtual_address; // Set the entry - *pte = create_page_table_entry((uintptr_t)physical, flags); - - // Invalidate the TLB - asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); + *pte = create_page_table_entry((uintptr_t)physical, flags | HugePageBit); _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); @@ -312,6 +330,17 @@ void PhysicalMemoryManager::map_area(virtual_address_t* virtual_address_start, s } +void PhysicalMemoryManager::map_area(physical_address_t* physical_address_start, virtual_address_t* virtual_address_start, size_t length, size_t flags) { + + // Get the size of the area + size_t size = size_to_frames(length); + + // Map the required frames + for (size_t i = 0; i < size; ++i) + map(physical_address_start + (i * PAGE_SIZE), virtual_address_start + (i * PAGE_SIZE), flags); + +} + void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, size_t flags) { // Map the physical address to its virtual address counter-part @@ -321,8 +350,6 @@ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, s void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { - //TODO: TEST WORKS - // Check if the address is mapped if(!is_mapped(0, (uintptr_t)virtual_address)) return; @@ -383,19 +410,30 @@ void PhysicalMemoryManager::clean_page_table(uint64_t *table) { table[i] = 0x00l; } } + +void clearBits(uint64_t *num, int start, int end) { + // Create a mask with 1s from start to end and 0s elsewhere + uint64_t mask = (~0ULL << start) ^ (~0ULL << (end + 1)); + + // Apply the mask to the number to clear the desired bits + *num &= ~mask; +} + pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) { - return (pte_t){ + pte_t page = (pte_t){ .present = 1, .write = (flags & WriteBit) != 0, .user = (flags & UserBit) != 0, .write_through = (flags & (1 << 7)) != 0, + .cache_disabled = 0, .accessed = 0, .dirty = 0, - .huge_page = 1, + .huge_page = (flags & HugePageBit) != 0, .global = 0, .available = 0, .physical_address = (uint64_t)address >> 12 }; + return page; } From 392f509f4f43803471c60ed7d4d1c19d1cc08b29 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 18 Apr 2024 13:43:48 +1200 Subject: [PATCH 22/29] USE 4KiB Pages --- kernel/include/memory/physical.h | 10 +-- kernel/src/hardwarecommunication/acpi.cpp | 1 - kernel/src/memory/physical.cpp | 80 ++++------------------- 3 files changed, 13 insertions(+), 78 deletions(-) diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index 862014fb..034d24c8 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -20,6 +20,7 @@ namespace MaxOS { #define PML4_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 3) #define PML3_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 2) #define PML2_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 1) + #define PML1_GET_INDEX(ADDR) PMLX_GET_INDEX(ADDR, 0) // Useful for readability typedef void virtual_address_t; @@ -80,13 +81,6 @@ namespace MaxOS { uint64_t* m_pml4_root_address; pte_t* m_pml4_root; - uint16_t get_pml4_index(uintptr_t virtual_address); - uint16_t get_page_directory_index(uintptr_t virtual_address); - uint16_t get_page_table_index(uintptr_t virtual_address); - uint16_t get_page_index(uintptr_t virtual_address); - uint64_t get_table_address(uint16_t pml4_index, uint16_t page_directory_index, uint16_t page_table_index, uint16_t page_index); - - void clean_page_table(uint64_t* table); pml_t* get_or_create_table(pml_t* table, size_t index, size_t flags); @@ -99,7 +93,7 @@ namespace MaxOS { // Vars - static const uint32_t PAGE_SIZE = { 0x200000 }; // 2MB + static const uint32_t PAGE_SIZE = { 0x1000 }; // 4096 bytes static const uint64_t PAGE_TABLE_OFFSET = { 0xFFFF000000000000 }; // The offset for the page table (before the kernel hihg half) // Frame Management diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index f037c77d..245a2317 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -22,7 +22,6 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s // Load the header m_header = &m_rsdt->header; - ASSERT(m_header->length > PhysicalMemoryManager::PAGE_SIZE, "RSDT needs more pages!") // Calculate the checksum uint8_t sum = 0; diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 0b5add71..baf3ebad 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -115,29 +115,6 @@ PhysicalMemoryManager::~PhysicalMemoryManager() { } -uint16_t PhysicalMemoryManager::get_pml4_index(uintptr_t virtual_address) { - // The PML4 index is the last byte - return (uint16_t)((uint64_t)virtual_address >> 39 & 0x1FF); -} - -uint16_t PhysicalMemoryManager::get_page_directory_index(uintptr_t virtual_address) { - // The PDP index is the 3rd byte - return (uint16_t)((uint64_t)virtual_address >> 30 & 0x1FF); -} -uint16_t PhysicalMemoryManager::get_page_table_index(uintptr_t virtual_address) { - // The PD index is the 2nd byte - return (uint16_t)((uint64_t)virtual_address >> 21 & 0x1FF); -} -uint16_t PhysicalMemoryManager::get_page_index(uintptr_t virtual_address) { - // The PT index is the 1st byte (starting from 12) - return (uint16_t)((uint64_t)virtual_address >> 12 & 0x1FF); -} - -uint64_t PhysicalMemoryManager::get_table_address(uint16_t pml4_index, uint16_t pdp_index, uint16_t page_table_index, uint16_t page_index) { - return (pml4_index << 39) | (pdp_index << 30) | (page_table_index << 21) | (page_index << 12); -} - - size_t PhysicalMemoryManager::size_to_frames(size_t size) { return align_to_page(size) / PAGE_SIZE; } @@ -294,16 +271,21 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt // Get the page directory pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); + // Get the page table + pml_t* pml1 = get_or_create_table(pml2, PML2_GET_INDEX(virtual_address), (flags | WriteBit)); + // Get the entry - uint64_t index = PML2_GET_INDEX(virtual_address); - pte_t* pte = &pml2->entries[PML2_GET_INDEX(virtual_address)]; + pte_t* pte = &pml1->entries[PML1_GET_INDEX(virtual_address)]; // Check if already mapped - if(pte->present) + if(pte->present){ + _kprintf("ADDRESS ALREADY PRESENT - FUCK"); return virtual_address; + } + // Set the entry - *pte = create_page_table_entry((uintptr_t)physical, flags | HugePageBit); + *pte = create_page_table_entry((uintptr_t)physical, flags); _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); @@ -350,21 +332,7 @@ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, s void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { - // Check if the address is mapped - if(!is_mapped(0, (uintptr_t)virtual_address)) - return; - - // Get the indexes of the address - uint16_t page_directory_pointer = get_pml4_index((uintptr_t)virtual_address); - uint16_t page_directory_index = get_page_directory_index((uintptr_t)virtual_address); - uint16_t page_table_index = get_page_table_index((uintptr_t)virtual_address); - - // Set the page entry in the page directory to 0 - uint64_t* page_directory = (uint64_t*)(PAGE_TABLE_OFFSET | get_table_address(510l, 510, (uint64_t) page_directory_pointer, (uint64_t) page_directory_index)); - page_directory[page_table_index] = 0; - - // Invalidate the TLB - asm volatile("invlpg (%0)" ::"r" ((uint64_t)virtual_address) : "memory"); + // TODO: Implement } /** @@ -375,33 +343,7 @@ void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { */ bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virtual_address) { - //TODO: Test works - - // Get the indexes of the address - uint16_t pml4_index = get_pml4_index(virtual_address); - uint16_t pdp_index = get_page_directory_index(virtual_address); - uint16_t page_table_index = get_page_table_index(virtual_address); - - // Check if there is a correct entry in the PML4 - if((m_pml4_root_address[pml4_index] & 1) == 0) - return false; - - // Get the address of the pointer to the page directory and check if it is valid - uint64_t* pdp_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, 510 , pdp_index)); - if((pdp_address[pdp_index] & 1) == 0) - return false; - - // Get the address to the page table and check if it is valid - uint64_t* pd_address = (uint64_t *)(PAGE_TABLE_OFFSET | get_table_address(510, 510, pdp_index, page_table_index)); - if((pd_address[page_table_index] & 1) == 0) - return false; - - // If the physical address is a nullpointer then don't bother checking if it is correct - if(physical_address == 0) - return true; - - // Check if the physical address is the same as the one in the page table - return align_to_page((size_t)physical_address) == align_to_page(pd_address[page_table_index]); + // TODO: Implement } From be57862c4fa4538f9f5b4ef32ff9a9798d6488a8 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Mon, 22 Apr 2024 11:24:18 +1200 Subject: [PATCH 23/29] USE 4KiB Pages (kernel mapping fix) --- kernel/src/asm/loader.s | 59 ++++++++++++++++++----- kernel/src/hardwarecommunication/acpi.cpp | 5 ++ kernel/src/memory/physical.cpp | 5 +- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index b52234f4..208c2114 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -1,6 +1,13 @@ ; Credit: https://github.com/dreamos82/Dreamos64/ +; DEFINES %define KERNEL_VIRTUAL_ADDR 0xFFFFFFFF80000000 +%define KERNEL_TABLES 2 +%define PRESENT_BIT 1 +%define WRITE_BIT 0b10 +%define PAGE_SIZE 0x1000 + +; VARS section .multiboot.text global start global p4_table @@ -18,15 +25,15 @@ start: ; Move the stack to the higher half mov esp, stack.top - KERNEL_VIRTUAL_ADDR - ; pm4l -> pdp -> pd -> page + ; pm4l -> pdp -> pd -> pt -> page ; = Configure the first entry in the P4 table to point the the P3 table = ; * p4_table = pm4l, p3_table = pdp * ; First we change the address to the higher half ; Then we set the writable and present bits ; Then we copy the address into the first entry of the p4_table - mov eax, p3_table - KERNEL_VIRTUAL_ADDR; - or eax, 0b11 + mov eax, p3_table - KERNEL_VIRTUAL_ADDR + or eax, PRESENT_BIT | WRITE_BIT mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; = Configure the the last entry in the P4 table to point the the P3 table = @@ -35,16 +42,25 @@ start: ; Then we set the writable and present bits ; Then we copy the address into the last entry of the p4_table mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR - or eax, 0b11 + or eax, PRESENT_BIT | WRITE_BIT mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 511 * 8], eax + ; = Configure p4 table to point to map itself = + ; * p4_table = pm4l * + ; First we change the address to the higher half + ; Then we set the writable and present bits + ; Then we copy the address into the last entry of the p4_table + mov eax, p4_table - KERNEL_VIRTUAL_ADDR + or eax, PRESENT_BIT | WRITE_BIT + mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax + ; = Configure the first entry in the P3 table to point the the P2 table = ; * p3_table = pdp, p2_table = pd * ; First we change the address to the higher half ; Then we set the writable and present bits ; Then we copy the address into the first entry of the p3_table mov eax, p2_table - KERNEL_VIRTUAL_ADDR - or eax, 0b11 + or eax, PRESENT_BIT | WRITE_BIT mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; = Configure the last entry in the P3 table to point the the P2 table = @@ -53,26 +69,41 @@ start: ; Then we set the writable and present bits ; Then we copy the address into the last entry of the p3_table mov eax, p2_table - KERNEL_VIRTUAL_ADDR - or eax, 0b11 + or eax, PRESENT_BIT | WRITE_BIT mov dword[(p3_table_hh - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax - ; = Loop through all the entries in the P2 table and set them to point to a 2MB page = - ; * p2_table = pd * + + ; = Loop through 2 page tables and map them = + mov ebx, 0 + mov eax, pt_tables - KERNEL_VIRTUAL_ADDR + .map_pd_table: + or eax, PRESENT_BIT | WRITE_BIT + mov dword[(p2_table - KERNEL_VIRTUAL_ADDR) + ebx * 8], eax + add eax, 0x1000 + inc ebx + cmp ebx, KERNEL_TABLES + jne .map_pd_table + + ; Now let's prepare a loop... + mov ecx, 0 ; Loop counter + + ; = Loop through all the entries in the P2 table and set them to point to a 4KiB page = ; First we set a counter for the loop ; Then we set the size of the page to 2MB ; Then we multiply the size of the page by the counter ; Then we set the huge page bit, writable and present ; Then we copy the address into the entry in the p2_table ; After that we increment the counter and check if we have reached the end of the table - mov ecx, 0 .map_p2_table: - mov eax, 0x200000 + mov eax, PAGE_SIZE mul ecx - or eax, 0b10000011 - mov [(p2_table - KERNEL_VIRTUAL_ADDR) + ecx * 8], eax + or eax, PRESENT_BIT | WRITE_BIT + + mov [(pt_tables - KERNEL_VIRTUAL_ADDR) + ecx * 8], eax inc ecx - cmp ecx, 512 + cmp ecx, 1024 + jne .map_p2_table ; = Load the P4 table into the cr3 register = @@ -153,6 +184,8 @@ p3_table_hh: resb 4096 p2_table: resb 4096 +pt_tables: + resb 8192 ; 2 tables for the kernel stack: resb 16384 .top: diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index 245a2317..034dcf88 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -33,6 +33,8 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s }else{ + // TODO: MAP THE MF + // If the new ACPI is not supported, panic ASSERT(multiboot->get_new_acpi() != 0, "No ACPI found!") @@ -89,6 +91,9 @@ ACPISDTHeader* AdvancedConfigurationAndPowerInterface::find(char const *signatur // Get the entry ACPISDTHeader* header = (ACPISDTHeader*) (m_type ? m_xsdt->pointers[i] : m_rsdt->pointers[i]); + // Move the header to the higher half + header = (ACPISDTHeader*) MemoryManager::to_higher_region((uint64_t)header); + // Check if the signature matches if(strncmp(header->signature, signature, 4) == 0) return header; diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index baf3ebad..1d996ce7 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -266,12 +266,15 @@ pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, si virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { // Get the page directory pointer m_pml4_root_address + _kprintf("l3: \n"); pml_t* pml3 = get_or_create_table((pml_t*)m_pml4_root_address, PML4_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the page directory + _kprintf("l2: \n"); pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the page table + _kprintf("l1: \n"); pml_t* pml1 = get_or_create_table(pml2, PML2_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the entry @@ -287,7 +290,7 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt // Set the entry *pte = create_page_table_entry((uintptr_t)physical, flags); - _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); + _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); } From 3bd23e50e79f757fe7b6155805bcbf4e1d512c62 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Tue, 9 Jul 2024 20:31:30 +1200 Subject: [PATCH 24/29] Flush TLB --- kernel/src/asm/loader.s | 2 +- kernel/src/memory/physical.cpp | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index 208c2114..0b8fdac4 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -187,7 +187,7 @@ p2_table: pt_tables: resb 8192 ; 2 tables for the kernel stack: - resb 16384 + resb 32768 ; 16 KiB stack .top: section .rodata diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 1d996ce7..1caf07f1 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -266,15 +266,13 @@ pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, si virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { // Get the page directory pointer m_pml4_root_address - _kprintf("l3: \n"); + pml_t* pml3 = get_or_create_table((pml_t*)m_pml4_root_address, PML4_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the page directory - _kprintf("l2: \n"); pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the page table - _kprintf("l1: \n"); pml_t* pml1 = get_or_create_table(pml2, PML2_GET_INDEX(virtual_address), (flags | WriteBit)); // Get the entry @@ -282,7 +280,7 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt // Check if already mapped if(pte->present){ - _kprintf("ADDRESS ALREADY PRESENT - FUCK"); + _kprintf("ADDRESS ALREADY PRESENT"); return virtual_address; } @@ -290,7 +288,12 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt // Set the entry *pte = create_page_table_entry((uintptr_t)physical, flags); - _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); + // Flush the TLB + asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); + +// _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); + + } From 57d00a06abea5c29cf2abd752f175073bc65d504 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Thu, 10 Oct 2024 16:12:13 +1300 Subject: [PATCH 25/29] PAGE MAPPING WORKS FUCK YEA --- .../hardwarecommunication/interrupts.h | 2 +- kernel/include/memory/memorymanagement.h | 15 +- kernel/include/memory/physical.h | 13 +- kernel/src/asm/loader.s | 345 ++++++++++++------ kernel/src/hardwarecommunication/acpi.cpp | 10 +- kernel/src/hardwarecommunication/apic.cpp | 15 +- .../src/hardwarecommunication/interrupts.cpp | 14 +- kernel/src/kernel.cpp | 19 +- kernel/src/linker.ld | 7 +- kernel/src/memory/memorymanagement.cpp | 46 ++- kernel/src/memory/physical.cpp | 295 +++++++++------ kernel/src/system/gdt.cpp | 36 +- kernel/src/system/multiboot.cpp | 5 +- toolchain/run_qemu.sh | 25 +- 14 files changed, 558 insertions(+), 289 deletions(-) diff --git a/kernel/include/hardwarecommunication/interrupts.h b/kernel/include/hardwarecommunication/interrupts.h index a25dc6e7..c7b1e3e2 100644 --- a/kernel/include/hardwarecommunication/interrupts.h +++ b/kernel/include/hardwarecommunication/interrupts.h @@ -61,7 +61,7 @@ namespace MaxOS { * @class InterruptManager * @brief Handles all interrupts and passes them to the correct handler */ - class InterruptManager : public common::InputStream { + class InterruptManager { friend class InterruptHandler; protected: diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index a205abda..f61f06ca 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace MaxOS{ @@ -38,8 +39,12 @@ namespace MaxOS{ public: static MemoryManager* s_active_memory_manager; - static const uint64_t s_higher_half_offset { 0xFFFFFFFF80000000 }; - static const uint64_t s_mem_io_offset { s_higher_half_offset - 0x100000000}; + + static const uint64_t s_higher_half_kernel_offset { 0xFFFFFFFF80000000 }; + static const uint64_t s_higher_half_mem_offset { 0xFFFF800000000000 }; + static const uint64_t s_higher_half_mem_reserved { 0x280000000 }; + static const uint64_t s_higher_half_offset { s_higher_half_mem_offset + s_higher_half_mem_reserved}; + static const uint64_t s_hh_direct_map_offset { s_higher_half_offset + PhysicalMemoryManager::PAGE_SIZE }; MemoryManager(multiboot_tag_mmap* memory_map); ~MemoryManager(); @@ -48,8 +53,10 @@ namespace MaxOS{ void free(void* pointer); int memory_used(); - static uint64_t to_higher_region(uint64_t physical_address); - static uint64_t to_io_region(uint64_t physical_address); + static void* to_higher_region(uintptr_t physical_address); + static void* to_lower_region(uintptr_t virtual_address); + static void* to_io_region(uintptr_t physical_address); + static void* to_dm_region(uintptr_t physical_address); }; } } diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index 034d24c8..c4416f5b 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -75,16 +75,24 @@ namespace MaxOS { uint32_t m_total_entries; uint32_t m_bitmap_size; uint32_t m_used_frames; + uint64_t m_memory_size; + + uint64_t m_anonymous_memory_physical_address; + uint64_t m_anonymous_memory_virtual_address; multiboot_mmap_entry* m_mmap; + multiboot_tag_mmap* m_mmap_tag; uint64_t* m_pml4_root_address; pte_t* m_pml4_root; + bool m_initialized; + void clean_page_table(uint64_t* table); - pml_t* get_or_create_table(pml_t* table, size_t index, size_t flags); + uint64_t* get_or_create_table(uint64_t* table, size_t index, size_t flags); pte_t create_page_table_entry(uintptr_t address, size_t flags); + uint64_t* get_bitmap_address(); public: @@ -116,8 +124,11 @@ namespace MaxOS { // Tools static size_t size_to_frames(size_t size); static size_t align_to_page(size_t size); + static size_t align_up_to_page(size_t size, size_t page_size); static bool check_aligned(size_t size); bool is_mapped(uintptr_t physical_address, uintptr_t virtual_address); + bool is_anonymous_available(size_t size); + bool is_multiboot_reserved(uint64_t address); static PhysicalMemoryManager* current_manager; }; diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index 0b8fdac4..a3c97b94 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -1,79 +1,99 @@ -; Credit: https://github.com/dreamos82/Dreamos64/ +%define MULTIBOOT_TAG_TYPE_END 0 +%define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +%define MULTIBOOT_TAG_TYPE_MMAP 6 +%define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +%define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 +%define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +%define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +struc multiboot_tag + .type: resd 1 + .size: resd 1 +endstruc + +struc multiboot_tag_framebuffer + .type: resd 1 + .size: resd 1 + .framebuffer_addr: resq 1 + .framebuffer_pitch: resd 1 + .framebuffer_width: resd 1 + .framebuffer_height: resd 1 + .framebuffer_bpp: resb 1 + .framebuffer_type: resb 1 + .reserved: resb 1 +endstruc + -; DEFINES %define KERNEL_VIRTUAL_ADDR 0xFFFFFFFF80000000 -%define KERNEL_TABLES 2 +%define PAGE_DIR_ENTRY_FLAGS 0b11 +%define SMALL_PAGES 1 %define PRESENT_BIT 1 %define WRITE_BIT 0b10 -%define PAGE_SIZE 0x1000 +%define HUGEPAGE_BIT 0b10000000 + +%if SMALL_PAGES == 1 +%define PAGE_SIZE 0x1000 ; PAGE_SIZE is 4k +%define PAGE_TABLE_ENTRY WRITE_BIT | PRESENT_BIT ;PAGE_TABLE_ENTRY for 4k pages, huge page bit is left to 0 +%define LOOP_LIMIT 1024 +%define PD_LOOP_LIMIT 2 +%elif SMALL_PAGES == 0 +%define PAGE_SIZE 0x200000 +%define PAGE_TABLE_ENTRY HUGEPAGE_BIT | WRITE_BIT | PRESENT_BIT ;PAGE_TABLE (pd table) entry for 2M pages, huge page bit is set. +%define LOOP_LIMIT 512 +%endif -; VARS section .multiboot.text global start +global p2_table global p4_table -extern callConstructors +global p3_table +global p3_table_hh +%if SMALL_PAGES == 1 +global pt_tables +%endif +global end_of_mapped_memory ;this variable will contain the virtual address of the last address mapped after bootstrap +global multiboot_framebuffer_data +global multiboot_mmap_data +global multiboot_basic_meminfo +global multiboot_acpi_info +global multiboot_tag_start +global multiboot_tag_end +global read_multiboot +global gdt64 +global stack + +; extern kernel_tss extern kernelMain [bits 32] start: + mov edi, ebx ; Address of multiboot structure + mov esi, eax ; Magic number - ; Put the multiboot header and magic number into the parameters of the kernelMain - mov edi, ebx - mov esi, eax - - ; Move the stack to the higher half mov esp, stack.top - KERNEL_VIRTUAL_ADDR - ; pm4l -> pdp -> pd -> pt -> page - - ; = Configure the first entry in the P4 table to point the the P3 table = - ; * p4_table = pm4l, p3_table = pdp * - ; First we change the address to the higher half - ; Then we set the writable and present bits - ; Then we copy the address into the first entry of the p4_table - mov eax, p3_table - KERNEL_VIRTUAL_ADDR - or eax, PRESENT_BIT | WRITE_BIT - mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax + mov eax, p3_table - KERNEL_VIRTUAL_ADDR; Copy p3_table address in eax + or eax, PRESENT_BIT | WRITE_BIT ; set writable and present bits to 1 + mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; Copy eax content into the entry 0 of p4 table - ; = Configure the the last entry in the P4 table to point the the P3 table = - ; * p4_table = pm4l, p3_table = pdp * - ; First we change the address to the higher half - ; Then we set the writable and present bits - ; Then we copy the address into the last entry of the p4_table - mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR + mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR ; This will contain the mapping of the kernel in the higher half or eax, PRESENT_BIT | WRITE_BIT mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 511 * 8], eax - ; = Configure p4 table to point to map itself = - ; * p4_table = pm4l * - ; First we change the address to the higher half - ; Then we set the writable and present bits - ; Then we copy the address into the last entry of the p4_table - mov eax, p4_table - KERNEL_VIRTUAL_ADDR + mov eax, p4_table - KERNEL_VIRTUAL_ADDR ; Mapping the PML4 into itself or eax, PRESENT_BIT | WRITE_BIT mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax - ; = Configure the first entry in the P3 table to point the the P2 table = - ; * p3_table = pdp, p2_table = pd * - ; First we change the address to the higher half - ; Then we set the writable and present bits - ; Then we copy the address into the first entry of the p3_table - mov eax, p2_table - KERNEL_VIRTUAL_ADDR - or eax, PRESENT_BIT | WRITE_BIT - mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax + mov eax, p2_table - KERNEL_VIRTUAL_ADDR ; Let's do it again, with p2_table + or eax, PRESENT_BIT | WRITE_BIT ; Set the writable and present bits + mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax ; Copy eax content in the 0th entry of p3 - ; = Configure the last entry in the P3 table to point the the P2 table = - ; * p3_table = pdp, p2_table = pd * - ; First we change the address to the higher half - ; Then we set the writable and present bits - ; Then we copy the address into the last entry of the p3_table mov eax, p2_table - KERNEL_VIRTUAL_ADDR or eax, PRESENT_BIT | WRITE_BIT mov dword[(p3_table_hh - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax - - ; = Loop through 2 page tables and map them = + %if SMALL_PAGES == 1 + ; If we are using 4k pages we have an extra level of tables to map mov ebx, 0 mov eax, pt_tables - KERNEL_VIRTUAL_ADDR .map_pd_table: @@ -81,67 +101,67 @@ start: mov dword[(p2_table - KERNEL_VIRTUAL_ADDR) + ebx * 8], eax add eax, 0x1000 inc ebx - cmp ebx, KERNEL_TABLES + cmp ebx, PD_LOOP_LIMIT jne .map_pd_table - + %endif ; Now let's prepare a loop... mov ecx, 0 ; Loop counter - ; = Loop through all the entries in the P2 table and set them to point to a 4KiB page = - ; First we set a counter for the loop - ; Then we set the size of the page to 2MB - ; Then we multiply the size of the page by the counter - ; Then we set the huge page bit, writable and present - ; Then we copy the address into the entry in the p2_table - ; After that we increment the counter and check if we have reached the end of the table .map_p2_table: - mov eax, PAGE_SIZE - mul ecx - or eax, PRESENT_BIT | WRITE_BIT + mov eax, PAGE_SIZE ; Size of the page + mul ecx ; Multiply by counter + or eax, PAGE_TABLE_ENTRY ; We set: huge page bit (if on 2M pages), writable and present + ; Moving the computed value into p2_table entry defined by ecx * 8 + ; ecx is the counter, 8 is the size of a single entry + %if SMALL_PAGES == 1 mov [(pt_tables - KERNEL_VIRTUAL_ADDR) + ecx * 8], eax - - inc ecx - cmp ecx, 1024 - - jne .map_p2_table - - ; = Load the P4 table into the cr3 register = - ; CR3 is the control register 3, it contains the address of the P4 table, however it can't be loaded directly - ; So we need to load it into eax and then copy it into cr3 + %elif SMALL_PAGES == 0 + mov [(p2_table - KERNEL_VIRTUAL_ADDR) + ecx * 8], eax + %endif + + inc ecx ; Let's increase ecx + cmp ecx, LOOP_LIMIT ; have we reached 512 ? (1024 for small pages) + ; When small pages is enabled: + ; each table is 4k size. Each entry is 8bytes + ; that is 512 entries in a table + ; when small pages enabled: two tables are adjacent in memory + ; they are mapped in the pdir during the map_pd_table cycle + ; this is why the loop is up to 1024 + + jne .map_p2_table ; if ecx < 512 then loop + + + ; All set... now we are nearly ready to enter into 64 bit + ; Is possible to move into cr3 only from another register + ; So let's move p4_table address into eax first + ; then into cr3 mov eax, (p4_table - KERNEL_VIRTUAL_ADDR) mov cr3, eax - ; = Enable PAE (Physical Address Extension) = - ; First we copy the value of cr4 into eax so we can change it - ; Then we set the Physical Address Extension bit - ; Then we copy the value back into cr4 + ; Now we can enable PAE + ; To do it we need to modify cr4, so first let's copy it into eax + ; we can't modify cr registers directly mov eax, cr4 - or eax, 1 << 5 + or eax, 1 << 5 ; Physical address extension bit mov cr4, eax - ; = Enable Long Mode = - ; First we use the rdmsr instruction to read the value of the msr 0xC0000080 into eax - ; Then we set the Long Mode Enable bit - ; Then we use the wrmsr instruction to write the value of eax into the msr 0xC0000080 + ; Now set up the long mode bit mov ecx, 0xC0000080 + ; rdmsr is to read a a model specific register (msr) + ; it copy the values of msr into eax rdmsr or eax, 1 << 8 + ; write back the value wrmsr - ; = Enable paging = - ; First we copy the value of cr0 into eax so we can change it - ; Then we set the Paging bit - ; Then we set the Write Protect bit this is to prevent the kernel from writing to read only pages - mov eax, cr0 - or eax, 1 << 31 - or eax, 1 << 16 - mov cr0, eax - - ; = Jump to the higher half = - ; First we load the address of the gdt into the gdtr - ; Then we set the code segment to 0x8 - ; Then we jump to the higher half + ; Now is time to enable paging + mov eax, cr0 ;cr0 contains the values we want to change + or eax, 1 << 31 ; Paging bit + or eax, 1 << 16 ; Write protect, cpu can't write to read-only pages when + ; privilege level is 0 + mov cr0, eax ; write back cr0 + ; load gdt lgdt [gdt64.pointer_low - KERNEL_VIRTUAL_ADDR] jmp (0x8):(kernel_jumper - KERNEL_VIRTUAL_ADDR) bits 64 @@ -150,6 +170,11 @@ section .text kernel_jumper: bits 64 + %if SMALL_PAGES == 0 + mov qword[(end_of_mapped_memory - KERNEL_VIRTUAL_ADDR)], (511 << 39) | (510 << 30) | (511 << 21) + %elif SMALL_PAGES == 1 + mov qword[(end_of_mapped_memory - KERNEL_VIRTUAL_ADDR)], (511 << 39) | (510 << 30) | ((PD_LOOP_LIMIT-1) << 21) | (511 << 12) + %endif ; update segment selectors mov ax, 0x10 mov ss, ax ; Stack segment selector @@ -158,55 +183,163 @@ kernel_jumper: mov fs, ax ; extra segment register mov gs, ax ; extra segment register + lea rax, [rdi+8] + + ;.bss section should be already 0 at least on unix and windows systems + ;no need to initialize + mov [multiboot_tag_start], rax + +read_multiboot: + ;Check if the tag is needed by the kernel, if yes store its address + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_FRAMEBUFFER + je .parse_fb_data + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_MMAP + je .mmap_tag_item + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_BASIC_MEMINFO + je .meminfo_tag_item + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_ACPI_OLD + je .acpi_item + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_ACPI_NEW + je .acpi_item + jmp .item_not_needed + .parse_fb_data: + mov [multiboot_framebuffer_data], rax + ; Here mapping the first 4mb(2mb using 4k pages) of framebuffer + ; The rest of the initialization will be done in the _init_basic_system functin + %if SMALL_PAGES == 0 + mov rbx, [(rax + multiboot_tag_framebuffer.framebuffer_addr)] + or rbx, PAGE_TABLE_ENTRY + mov qword [(p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 488], rbx + add rbx, PAGE_SIZE + or rbx, PAGE_TABLE_ENTRY + mov qword [(p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 489], rbx + %else + mov rcx, 0 + mov rbx, fbb_pt_tables - KERNEL_VIRTUAL_ADDR + or rbx, PRESENT_BIT | WRITE_BIT + mov qword [(p2_table) + 8 * 488], rbx + mov rbx, [rax + multiboot_tag_framebuffer.framebuffer_addr] + .map_fb: + or rbx, PAGE_TABLE_ENTRY + mov qword [(fbb_pt_tables) + 8 * rcx], rbx + add rbx, PAGE_SIZE + inc rcx + cmp rcx, 512 + jne .map_fb + ;mov qword [p2_table + 8 * 488], + %endif + jmp .item_not_needed + .mmap_tag_item: + mov [multiboot_mmap_data], rax + jmp .item_not_needed + .acpi_item: + mov [multiboot_acpi_info], rax + jmp .item_not_needed + .meminfo_tag_item: + mov [multiboot_basic_meminfo], rax + .item_not_needed: + mov ebx, dword [rax + multiboot_tag.size] + ;Next tag is at current_tag_address + current_tag size + ;lea rax, [rax + rbx + 7] + add rax, rbx + ;Padded with 0 until the first byte aligned with 8bytes + add rax, 7 + and rax, ~7 + ;Check if the tag is the end tag + ;Type: 0 Size: 8 + ;multiboot_tag.type == 0? + cmp dword [rax + multiboot_tag.type], MULTIBOOT_TAG_TYPE_END + jne read_multiboot + ; && multiboot_tag.size == 8? + cmp dword [rax + multiboot_tag.size], 8 + jne read_multiboot + add rax, multiboot_tag.size + mov qword [multiboot_tag_end], rax + mov rax, higher_half jmp rax higher_half: ; Far jump to long mode - mov edx, 0xDEADBEEF - mov rsp, stack.top - lgdt [gdt64.pointer] - ; Run the kernel - call callConstructors + ; The two lines below are needed to un map the kernel in the lower half + mov eax, 0x0 + mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 0], eax + + mov rax, cr3 + mov cr3, rax call kernelMain section .bss align 4096 -p4_table: +p4_table: ;PML4 resb 4096 -p3_table: +p3_table: ;PDPR resb 4096 -p3_table_hh: +p3_table_hh: ;PDPR resb 4096 -p2_table: +p2_table: ;PDP resb 4096 + +%if SMALL_PAGES == 1 +; if SMALL_PAGES is defined it means we are using 4k pages +; For now the first 8mb will be mapped for the kernel. +; We reserve 8192 bytes, because we are going to fill 2 page tables pt_tables: - resb 8192 ; 2 tables for the kernel + resb 8192 +fbb_pt_tables: + resb 8192 +%endif + +; This section will be used to get the multiboot info +align 4096 +end_of_mapped_memory: + resq 1 +multiboot_tag_end: + resq 1 +multiboot_tag_start: + resq 1 +multiboot_framebuffer_data: + resb 8 +multiboot_mmap_data: + resb 8 +multiboot_basic_meminfo: + resb 8 +multiboot_acpi_info: + resb 8 stack: - resb 32768 ; 16 KiB stack + resb 16384 .top: -section .rodata - +section .data ; gdt table needs at least 3 entries: ; the first entry is always null ; the other two are data segment and code segment. +; the last two are data and code segments for user mode. gdt64: dq 0 ;first entry = 0 .code equ $ - gdt64 + ; equ tells the compiler to set the address of the variable at given address ($ - gdt64). $ is the current position. ; set the following values: ; descriptor type: bit 44 has to be 1 for code and data segments ; present: bit 47 has to be 1 if the entry is valid ; read/write: bit 41 1 means that is readable ; executable: bit 43 it has to be 1 for code segments ; 64bit: bit 53 1 if this is a 64bit gdt - dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) ;second entry=code=8 + dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) ;second entry=code=0x8 .data equ $ - gdt64 - dq (1 << 44) | (1 << 47) | (1 << 41) ;third entry = data = 10 + dq (1 << 44) | (1 << 47) | (1 << 41) ;third entry = data = 0x10 + .ucode equ $ - gdt64 + dq (1 <<44) | (1 << 47) | (1 << 41) | (1 << 43) | (1 << 53) | (3 << 45) ;fourth entry=code=0x18 + .udata equ $ - gdt64 + dq (1 << 44) | (1 << 47) | (1 << 41) | (3 << 45) ;fifth entry = data = 0x20 + .tss_low equ $ - gdt64 ;sixth entry placeholder for TSS entry lower part + dq 0 + .tss_high equ $ - gdt64 ; seventh entry placeholder for TSS entry higher part + dq 0 .pointer: dw .pointer - gdt64 - 1 diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index 034dcf88..3d348482 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -12,16 +12,23 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s if(multiboot->get_old_acpi() != 0){ + _kprintf("Using old ACPI\n"); + // Get the RSDP & RSDT RSDPDescriptor* rsdp = (RSDPDescriptor*)(multiboot->get_old_acpi() + 1); m_rsdt = (RSDT*) rsdp->rsdt_address; // Map the RSDT - PhysicalMemoryManager::current_manager->map(VirtualPointer(m_rsdt), VirtualPointer(MemoryManager::to_higher_region((uint64_t)m_rsdt)), PageFlags::Write); + PhysicalMemoryManager::current_manager->map(m_rsdt, MemoryManager::to_io_region((uint64_t)m_rsdt), Present | Write); m_rsdt = (RSDT*) MemoryManager::to_higher_region((uint64_t)m_rsdt); + _kprintf("RSDT: physical: 0x%x, virtual: 0x%x\n", rsdp->rsdt_address, m_rsdt); + // Load the header m_header = &m_rsdt->header; + if((m_header->length / PhysicalMemoryManager::PAGE_SIZE + 1) > 1) { + ASSERT(false, "RSDT is too big, need to map more pages!") + } // Calculate the checksum uint8_t sum = 0; @@ -34,6 +41,7 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s }else{ // TODO: MAP THE MF + ASSERT(false, "Not implemented!") // If the new ACPI is not supported, panic ASSERT(multiboot->get_new_acpi() != 0, "No ACPI found!") diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index 1d57181d..dc96a487 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -43,10 +43,9 @@ void LocalAPIC::init() { _kprintf("CPU supports xAPIC\n"); // Map the APIC base address to the higher half - m_apic_base_high = MemoryManager::to_io_region(m_apic_base); - PhysicalMemoryManager::current_manager->map(VirtualPointer(m_apic_base), VirtualPointer(m_apic_base_high), Write); - _kprintf("APIC Base: 0x%x\n", m_apic_base); - _kprintf("APIC Higher Half: 0x%x\n", m_apic_base_high); + m_apic_base_high = (uint64_t)MemoryManager::to_io_region(m_apic_base); + PhysicalMemoryManager::current_manager->map(m_apic_base, m_apic_base_high, Write); + _kprintf("APIC Base: phy=0x%x, virt=0x%x\n", m_apic_base, m_apic_base_high); } else { ASSERT(false, "CPU does not support xAPIC") @@ -122,11 +121,9 @@ void IOAPIC::init() { m_address = io_apic->io_apic_address; // Map the IO APIC address to the higher half - m_address_high = MemoryManager::to_io_region(m_address); - PhysicalMemoryManager::current_manager->map(VirtualPointer(m_address), VirtualPointer(m_address_high), Write); - - _kprintf("IO APIC Address: 0x%x\n", m_address); - _kprintf("IO APIC Higher Half: 0x%x\n", m_address_high); + m_address_high = (uint64_t)MemoryManager::to_higher_region(m_address); + _kprintf("IO APIC Address: phy=0x%x, virt=0x%x\n", m_address, m_address_high); + PhysicalMemoryManager::current_manager->map(VirtualPointer(m_address), VirtualPointer(m_address_high), Write);; // Get the IO APIC version and max redirection entry m_version = read(0x01); diff --git a/kernel/src/hardwarecommunication/interrupts.cpp b/kernel/src/hardwarecommunication/interrupts.cpp index e334b767..390488cb 100644 --- a/kernel/src/hardwarecommunication/interrupts.cpp +++ b/kernel/src/hardwarecommunication/interrupts.cpp @@ -45,7 +45,7 @@ void InterruptHandler::handle_interrupt() { InterruptManager::InterruptManager(uint16_t hardware_interrupt_offset, OutputStream* handler) -: common::InputStream(handler), +: m_hardware_interrupt_offset(hardware_interrupt_offset) { @@ -182,6 +182,18 @@ void InterruptManager::deactivate() */ system::cpu_status_t* InterruptManager::HandleInterrupt(system::cpu_status_t *status) { + if(status -> interrupt_number == 0xE) + { + bool present = (status ->error_code & 0x1) != 0; // Bit 0: Page present flag + bool write = (status ->error_code & 0x2) != 0; // Bit 1: Write operation flag + bool user_mode = (status ->error_code & 0x4) != 0; // Bit 2: User mode flag + bool reserved_write = (status ->error_code & 0x8) != 0; // Bit 3: Reserved bit write flag + bool instruction_fetch = (status ->error_code & 0x10) != 0; // Bit 4: Instruction fetch flag (on some CPUs) + + ASSERT(false, "Page Fault (0x%x): present: %s, write: %s, user-mode: %s, reserved write: %s, instruction fetch: %s\n", + status->error_code, (present ? "Yes" : "No"), (write ? "Yes" : "No"), (user_mode ? "Yes" : "No"), (reserved_write ? "Yes" : "No"), (instruction_fetch ? "Yes" : "No")); + } + ASSERT(false, "Interupt number 0x%x, Code: 0x%x", status->interrupt_number, status->error_code); // If there is an interrupt manager handle interrupt diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 9b0aa6ed..8cad1135 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -116,34 +116,35 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) // Make the multiboot header Multiboot multiboot(addr); - _kprintf("MaxOS booted\n"); + _kprintf("-= MaxOS booted =-\n"); //GlobalDescriptorTable gdt; //_kprintf("GDT set up\n"); InterruptManager interrupts(0x20, 0); - _kprintf("IDT set up\n"); + _kprintf("-= IDT set up =-\n"); - uint32_t mbi_size = *(uint32_t *) (addr + MemoryManager::s_higher_half_offset); + uint32_t mbi_size = *(uint32_t *) (addr + MemoryManager::s_higher_half_kernel_offset); PhysicalMemoryManager pmm(addr + mbi_size, &multiboot, p4_table); - _kprintf("Physical Memory Manager set up \n"); - _kprintf("Verify Page Root Address: 0x%x\n", &p4_table); + _kprintf("-= Physical Memory Manager set up =-\n"); + + // TODO: VMM AdvancedConfigurationAndPowerInterface acpi(&multiboot); - _kprintf("ACPI set up\n"); + _kprintf("-= ACPI set up =-\n"); AdvancedProgrammableInterruptController apic(&acpi); - _kprintf("APIC set up\n"); + _kprintf("-= APIC set up =-\n"); interrupts.activate(); - _kprintf("IDT activated\n"); + _kprintf("-= IDT activated =-\n"); // TODO: 64 bit architecture rewrite // - Fix Paging // - Finish ACPI // - Memory Allocation // - Convert old codebase - _kprintf("KERNEL DONE\n"); + _kprintf("-= KERNEL DONE =-\n"); while (true) { //TODO: This causes a Double Fault and then infinte General Protection Faults system::CPU::halt(); diff --git a/kernel/src/linker.ld b/kernel/src/linker.ld index ad0cb2f5..df5865df 100644 --- a/kernel/src/linker.ld +++ b/kernel/src/linker.ld @@ -21,19 +21,22 @@ SECTIONS { .text ALIGN (4K) : AT (ADDR (.text) - _kern_virtual_offset) { *(.text) + *(.text.*) } .rodata ALIGN (4K) : AT (ADDR (.rodata) - _kern_virtual_offset) { *(.rodata) + *(.rodata.*) } .data ALIGN (4K) : AT (ADDR (.data) - _kern_virtual_offset) { - start_ctors = .; + start_ctors = .; KEEP(*( .init_array )); KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); end_ctors = .; *(.data) + *(.data.*) } .bss ALIGN (4K) : AT (ADDR (.bss) - _kern_virtual_offset) { @@ -41,4 +44,6 @@ SECTIONS { } _kernel_end = .; + _kernel_size = _kernel_end - _kernel_start - _kern_virtual_offset; + _kernel_physical_end = . - _kern_virtual_offset; } \ No newline at end of file diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index ac1aae47..c626d45a 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -157,32 +157,46 @@ int MemoryManager::memory_used() { return result; } -uint64_t MemoryManager::to_higher_region(uint64_t physical_address) { +void* MemoryManager::to_higher_region(uintptr_t physical_address) { - // Check if the address is already mapped - if(physical_address >= s_higher_half_offset) - return physical_address; + // If it's in the lower half then add the offset + if(physical_address < s_higher_half_kernel_offset) + return (void*)(physical_address + s_higher_half_kernel_offset); + + // Must be in the higher half + return (void*)physical_address; - // Map the address to the higher half - return physical_address + s_higher_half_offset; } -uint64_t MemoryManager::to_io_region(uint64_t physical_address) { +void *MemoryManager::to_lower_region(uintptr_t virtual_address) { + // If it's in the lower half then add the offset + if(virtual_address > s_higher_half_kernel_offset) + return (void*)(virtual_address - s_higher_half_kernel_offset); + + // Must be in the lower half + return (void*)virtual_address; +} - // Check if the address is already mapped - if(physical_address >= s_mem_io_offset) - return physical_address; +void *MemoryManager::to_io_region(uintptr_t physical_address) { - // Check if the address is past 4GB - if(physical_address >= 0xFFFFFFFF) - return physical_address; + if(physical_address < s_higher_half_mem_offset) + return (void*)(physical_address + s_higher_half_mem_offset); + + // Must be in the higher half + return (void*)physical_address; - // Map the address to the higher half - return physical_address + s_mem_io_offset; } +void *MemoryManager::to_dm_region(uintptr_t physical_address) { -//Redefine the default object functions with memory orientated ones (defaults disabled in makefile) + if(physical_address < s_higher_half_offset) + return (void*)(physical_address + s_hh_direct_map_offset); + // Must be in the higher half + return (void*)physical_address; + +} + +//Redefine the default object functions with memory orientated ones (defaults disabled in makefile) void* operator new(size_t size) throw(){ diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 1caf07f1..67eef0d5 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -10,107 +10,107 @@ using namespace MaxOS::system; extern uint64_t p4_table[]; PhysicalMemoryManager* PhysicalMemoryManager::current_manager = nullptr; +extern uint64_t _kernel_end; +extern uint64_t _kernel_size; +extern uint64_t _kernel_physical_end; +extern uint64_t multiboot_tag_end; +extern uint64_t multiboot_tag_start; -MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot, uint64_t pml4_root[512]){ +MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot, uint64_t pml4_root[512]) { // SEE boot.s FOR SETUP OF PAGING - m_pml4_root = (pte_t*)pml4_root; + m_pml4_root = (pte_t *)pml4_root; m_pml4_root_address = pml4_root; // Set the current manager current_manager = this; // Store the information about the bitmap - uint64_t memory_size = (multiboot->get_basic_meminfo() -> mem_upper + 1024) * 1024; - m_bitmap_size = memory_size / PAGE_SIZE + 1; + m_memory_size = multiboot->get_basic_meminfo()->mem_upper + 1024; + m_bitmap_size = m_memory_size / PAGE_SIZE + 1; m_total_entries = m_bitmap_size / ROW_BITS + 1; + _kprintf("Mem Info: size = %dmb, bitmap size = %d, total entries = %d, page size = %db\n", (m_memory_size * 1024) / 1024 / 1024, m_bitmap_size, m_total_entries, PAGE_SIZE); - // Loop through all the memory map entries - multiboot_tag_mmap* mmap = multiboot->get_mmap(); - for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + // Get the mmap that stores the memory to use + m_mmap_tag = multiboot->get_mmap(); + for (multiboot_mmap_entry *entry = m_mmap_tag->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap_tag->entry_size)) { // Skip if the region is not free or there is not enough space if (entry->type != MULTIBOOT_MEMORY_AVAILABLE || (entry->addr + entry->len) < reserved) continue; + // We want the last entry m_mmap = entry; - break; } + _kprintf("Mmap in use: 0x%x - 0x%x\n", m_mmap->addr, m_mmap->addr + m_mmap->len); + + // Kernel Memory (anonymous memory to the next page) + _kprintf("Kernel Memory: kernel_end = 0x%x, kernel_size = 0x%x, kernel_physical_end = 0x%x\n", &_kernel_end, &_kernel_size, &_kernel_physical_end); + m_anonymous_memory_physical_address = (uint64_t)align_up_to_page((size_t)(&_kernel_physical_end + PAGE_SIZE), PAGE_SIZE); + m_anonymous_memory_virtual_address = (uint64_t)align_up_to_page((size_t)(&_kernel_end + PAGE_SIZE), PAGE_SIZE); + _kprintf("Anonymous Memory: physical = 0x%x, virtual = 0x%x\n", m_anonymous_memory_physical_address, m_anonymous_memory_virtual_address); + + // Map the physical memory into the virtual memory + uint64_t physical_address = 0; + uint64_t virtual_address = MemoryManager::s_hh_direct_map_offset; + uint64_t mem_end = m_mmap->addr + m_mmap->len; + + while (physical_address < mem_end) { + map((physical_address_t *)physical_address, (virtual_address_t *)virtual_address, Present | Write); + physical_address += PAGE_SIZE; + virtual_address += PAGE_SIZE; + } + _kprintf("Mapped: physical = 0x%x-0x%x, virtual = 0x%x-0x%x\n", 0, physical_address, MemoryManager::s_hh_direct_map_offset, virtual_address); // TODO: FAILS WHEN TRYING WITH LIKE 2Gb Mem - // Check if the reserved area is part of the mmap - size_t offset = 0; - if(reserved > m_mmap -> addr) - offset = reserved - m_mmap -> addr; - - // Use the memory - m_bit_map = (uint64_t *)(m_mmap->addr + offset); + // Get the bitmap & clear it + m_anonymous_memory_physical_address += PAGE_SIZE; + m_bit_map = get_bitmap_address(); - // Free all the entries for (uint32_t i = 0; i < m_total_entries; ++i) m_bit_map[i] = 0; + _kprintf("Bitmap: location = 0x%x - 0x%x\n", m_bit_map, m_bit_map + m_bitmap_size / 8); // Calculate how much space the kernel takes up - uint32_t kernel_entries = (reserved / PAGE_SIZE) + 1; - if((((uint32_t)(reserved)) % PAGE_SIZE) != 0){ - // This means that there is kernel modules since there is spare space after one page - kernel_entries += 1; + uint32_t kernel_entries = (m_anonymous_memory_physical_address / PAGE_SIZE) + 1; + if ((((uint32_t)(m_anonymous_memory_physical_address)) % PAGE_SIZE) != 0) { + // If the kernel takes up more then a whole page(s) + kernel_entries += 1; } // Reserve the kernel in the bitmap - m_bit_map[kernel_entries / 64] = ~(~(0ul) << (kernel_entries % 64)); + uint32_t kernel_rows = kernel_entries / ROW_BITS; + for (uint32_t i = 0; i < kernel_rows; ++i) + m_bit_map[i] = 0xFFFFFFFF; + + // Change the final row to account for the remaining bits + m_bit_map[kernel_rows] = ~(0ul) << (kernel_entries - (kernel_rows * 64)); + m_used_frames = kernel_entries; + _kprintf("Kernel: entries = %d, rows = %d, used = %d\n", kernel_entries, kernel_rows, m_used_frames); // Reserve the area for the bitmap - allocate_area((uint64_t)m_bit_map, (m_bitmap_size / 8) + 1); + allocate_area((uint64_t)MemoryManager::to_lower_region((uint64_t)m_bit_map), m_bitmap_size / 8 + 1); // Reserve the area for the mmap - for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + for (multiboot_mmap_entry *entry = m_mmap_tag->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap_tag->entry_size)) { // Check if the entry is to be mapped - if(entry->type <= 1) + if (entry->type <= 1) continue; - allocate_area(entry->addr, entry->len); - } - - // Log where the bitmap starts - _kprintf("Bitmap starts at: 0x%x\n", m_bit_map); - _kprintf("Bitmap size: %d\n", m_bitmap_size); - _kprintf("Bitmap end: 0x%x\n", m_bit_map + m_bitmap_size / 8); - _kprintf("Free memory: %dmb/%dmb (from 0x%x to 0x%x)\n", m_mmap->len / 1024 / 1024, memory_size / 1024 / 1024, m_mmap->addr, m_mmap->addr + m_mmap->len); - - return; - - // Allocate a new PML4 root - m_pml4_root_address = (uint64_t*)allocate_frame(); - m_pml4_root = (pte_t*)m_pml4_root_address; - - // Map the first two pages for the kernel - map_area((physical_address_t*)0, (virtual_address_t*)MemoryManager::s_higher_half_offset, PAGE_SIZE * 2, Present); - - // Map 4 GB of physical memory - _kprintf("Mapping 4Gb Of io region...\n"); - map_area((physical_address_t*)0, (virtual_address_t*)MemoryManager::s_active_memory_manager -> to_io_region(0), 0xFFFFFFFF, Write); - - // Re-map the mmap - for (multiboot_mmap_entry *entry = mmap->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)mmap + mmap->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + mmap->entry_size)) { + // Where our free mem starts + if(entry->addr >= mem_end) + continue; - // Check this + // Reserve the area - // 4GB Already mapped - if(entry->addr >= 0xFFFFFFFF) - continue; - - _kprintf("Mapping (io) mmap 0x%x - 0x%x\n", entry->addr, entry -> addr + entry->len); - map_area((physical_address_t*)entry->addr, (virtual_address_t *)MemoryManager::s_active_memory_manager -> to_io_region(entry->addr), entry -> len, Write); + allocate_area(entry->addr, entry->len); + _kprintf("Mmap Reserved: 0x%x - 0x%x\n", entry->addr, entry->addr + entry->len); } - - // Load the new PML4 - asm volatile("mov %0, %%cr3" :: "r"(m_pml4_root_address)); - + // Initialisation Done + m_initialized = true; } - PhysicalMemoryManager::~PhysicalMemoryManager() { } @@ -124,12 +124,35 @@ size_t PhysicalMemoryManager::align_to_page(size_t size) { return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); } +size_t PhysicalMemoryManager::align_up_to_page(size_t size, size_t page_size) { + return (size + page_size - 1) & ~(page_size - 1); +} + + bool PhysicalMemoryManager::check_aligned(size_t size){ return (size % PAGE_SIZE) == 0; } void* PhysicalMemoryManager::allocate_frame() { + // Check if the pmm is initialized + if(!m_initialized){ + + // Find the first free frame + while ((!is_anonymous_available(m_anonymous_memory_physical_address)) && (m_anonymous_memory_physical_address < m_memory_size)) { + m_anonymous_memory_physical_address += PAGE_SIZE; + m_anonymous_memory_virtual_address += PAGE_SIZE; + } + + // Mark frame as used + m_anonymous_memory_physical_address += PAGE_SIZE; + m_anonymous_memory_virtual_address += PAGE_SIZE; + + // Return the address + return (void*)(m_anonymous_memory_physical_address - PAGE_SIZE); + + } + // Check if there are enough frames if(m_used_frames >= m_bitmap_size) return nullptr; @@ -233,68 +256,50 @@ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { } -pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, size_t flags) { - - // Get the entry from the table - pte_t entry = table->entries[index]; - - // Check if the entry is present - if(entry.present) { - - // Get the address of the table - return (pml_t*)(entry.physical_address << 12); - - } - - _kprintf("Creating new table at index: %d\n", index); - - // Need to create a new table - pml_t* new_table = (pml_t*)allocate_frame(); - - // Clean the table - clean_page_table((uint64_t*)new_table); - - // Set the entry - table->entries[index] = create_page_table_entry((uintptr_t)new_table, flags); - - return new_table; - - -} -virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags) { +virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_address, virtual_address_t* address, size_t flags) { +#define SIGN_EXTENSION 0xFFFF000000000000 +#define ENTRIES_TO_ADDRESS(pml4, pdpr, pd, pt)((pml4 << 39) | (pdpr << 30) | (pd << 21) | (pt << 12)) - // Get the page directory pointer m_pml4_root_address + uint64_t* pml4_table = m_pml4_root_address; - pml_t* pml3 = get_or_create_table((pml_t*)m_pml4_root_address, PML4_GET_INDEX(virtual_address), (flags | WriteBit)); + uint16_t pml4_e = PML4_GET_INDEX((uint64_t) address); + uint16_t pdpr_e = PML3_GET_INDEX((uint64_t) address); + uint16_t pd_e = PML2_GET_INDEX((uint64_t) address); + uint16_t pt_e = PML1_GET_INDEX((uint64_t) address); - // Get the page directory - pml_t* pml2 = get_or_create_table(pml3, PML3_GET_INDEX(virtual_address), (flags | WriteBit)); + uint64_t *pdpr_table =(uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l,510l,510l, (uint64_t) pml4_e)); + uint64_t *pd_table = (uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l,510l, (uint64_t) pml4_e, (uint64_t) pdpr_e)); + uint64_t *pt_table = (uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l, (uint64_t) pml4_e, (uint64_t) pdpr_e, (uint64_t) pd_e)); - // Get the page table - pml_t* pml1 = get_or_create_table(pml2, PML2_GET_INDEX(virtual_address), (flags | WriteBit)); - // Get the entry - pte_t* pte = &pml1->entries[PML1_GET_INDEX(virtual_address)]; + if( !(pml4_table[pml4_e] & 0b1) ) { + uint64_t *new_table = (uint64_t *)allocate_frame(); + pml4_table[pml4_e] = (uint64_t) new_table | Present | Write; + clean_page_table(pdpr_table); + } - // Check if already mapped - if(pte->present){ - _kprintf("ADDRESS ALREADY PRESENT"); - return virtual_address; + if( !(pdpr_table[pdpr_e] & 0b1) ) { + uint64_t *new_table = (uint64_t *)allocate_frame(); + pdpr_table[pdpr_e] = (uint64_t) new_table | Present | Write; + clean_page_table(pd_table); } + if( !(pd_table[pd_e] & 0b01) ) { + uint64_t *new_table = (uint64_t *)allocate_frame(); + pd_table[pd_e] = (uint64_t) new_table | Present | Write; + clean_page_table(pt_table); + } - // Set the entry - *pte = create_page_table_entry((uintptr_t)physical, flags); + if( !(pt_table[pt_e] & 0b1)) { + pt_table[pt_e] = (uint64_t) physical_address | flags; + } // Flush the TLB - asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); - -// _kprintf("Mapped: 0x%x to 0x%x\n", physical, virtual_address); - - + asm volatile("invlpg (%0)" ::"r" (address) : "memory"); + return address; } virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address, size_t flags) { @@ -337,7 +342,7 @@ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, s } void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { - + ASSERT(false, "Not implemented!") // TODO: Implement } @@ -348,7 +353,7 @@ void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { * @return True if the physical address is mapped to the virtual address */ bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virtual_address) { - + ASSERT(false, "Not implemented!") // TODO: Implement } @@ -385,3 +390,73 @@ pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t f return page; } + +bool PhysicalMemoryManager::is_anonymous_available(size_t address) { + + // Return false if the address range is entirely within or overlaps with the multiboot reserved region + if ((address > multiboot_tag_start && address + PAGE_SIZE < multiboot_tag_end) || (address + PAGE_SIZE > multiboot_tag_start && address < multiboot_tag_end)) { + return false; + } + + // Loop through the mmmap entries + for (multiboot_mmap_entry *entry = m_mmap_tag->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap_tag->entry_size)) { + + // If it doesn't overlap with the mmap entry + if ((entry -> addr + entry -> len) < (address + PAGE_SIZE)) + continue; + + // If it is not available + if(entry -> type != MULTIBOOT_MEMORY_AVAILABLE) + continue; + + // Check if the address is reserved by the multiboot module + if(is_multiboot_reserved(address)) + continue; + + // Memory is available + return true; + + } + + // Memory is not available + return false; +} +bool PhysicalMemoryManager::is_multiboot_reserved(uint64_t address) { + //ASSERT(false, "Not implemented!") + // TODO: Check if address is reserve by multiboot module + + return false; +} +uint64_t *PhysicalMemoryManager::get_bitmap_address() { + + + // Earliest address to place the bitmap (after the kernel and hh direct map) + uint64_t limit = m_anonymous_memory_physical_address; + + // Loop through the mmap entries + for (multiboot_mmap_entry *entry = m_mmap_tag->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap_tag->entry_size)) { + + // If the entry is not available or the address is before the limit + if (entry -> type != MULTIBOOT_MEMORY_AVAILABLE || entry -> len > limit) + continue; + + size_t space = entry -> len; + size_t offset = 0; + + // If the entry starts before the limit then adjust the space to start where the limit is + if(entry -> addr < limit){ + offset = limit - entry -> addr; + space -= offset; + } + + + // Make sure there is enough space + ASSERT(space >= (m_bitmap_size / 8 + 1), "Not enough space for the bitmap"); + + // Return the address + return (uint64_t*)MemoryManager::to_dm_region(entry -> addr + offset); + } + + // Error no space for the bitmap + ASSERT(false, "No space for the bitmap"); +} diff --git a/kernel/src/system/gdt.cpp b/kernel/src/system/gdt.cpp index 6eca294d..08f32813 100644 --- a/kernel/src/system/gdt.cpp +++ b/kernel/src/system/gdt.cpp @@ -48,24 +48,26 @@ GlobalDescriptorTable::GlobalDescriptorTable() .address = (uint64_t)m_gdt }; - // Load the GDTR - asm volatile("lgdt %0" : : "m" (gdtr)); - _kprintf("Loaded GDT\n"); - - // Reload the segment registers - asm volatile("\ - mov $0x10, %ax \n\ - mov %ax, %ds \n\ - mov %ax, %es \n\ - mov %ax, %fs \n\ - mov %ax, %gs \n\ - mov %ax, %ss \n\ - \n\ - pop %rdi \n\ - push $0x8 \n\ - push %rdi \n\ - "); + // TODO: This is done in assembly but would be nice to do here +// // Load the GDTR +// asm volatile("lgdt %0" : : "m" (gdtr)); +// +// _kprintf("Loaded GDT\n"); +// +// // Reload the segment registers +// asm volatile("\ +// mov $0x10, %ax \n\ +// mov %ax, %ds \n\ +// mov %ax, %es \n\ +// mov %ax, %fs \n\ +// mov %ax, %gs \n\ +// mov %ax, %ss \n\ +// \n\ +// pop %rdi \n\ +// push $0x8 \n\ +// push %rdi \n\ +// "); _kprintf("Reloaded segment registers\n"); diff --git a/kernel/src/system/multiboot.cpp b/kernel/src/system/multiboot.cpp index 5f50bf85..85bcd643 100644 --- a/kernel/src/system/multiboot.cpp +++ b/kernel/src/system/multiboot.cpp @@ -4,8 +4,11 @@ #include #include +#include + using namespace MaxOS; using namespace MaxOS::system; +using namespace MaxOS::memory; Multiboot::Multiboot(unsigned long addr) { @@ -13,7 +16,7 @@ Multiboot::Multiboot(unsigned long addr) { // Loop through the tags and load them struct multiboot_tag *tag; - for(tag=(struct multiboot_tag *)(addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7))) { + for(tag=(struct multiboot_tag *)(addr + MemoryManager::s_higher_half_kernel_offset + 8); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7))) { switch (tag -> type) { case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: diff --git a/toolchain/run_qemu.sh b/toolchain/run_qemu.sh index 2e9d4669..b1d05033 100755 --- a/toolchain/run_qemu.sh +++ b/toolchain/run_qemu.sh @@ -136,20 +136,21 @@ fi # Create the args QEMU_ARGS="" -QEMU_ARGS="$QEMU_ARGS -m 2G" # 2 GB of RAM -QEMU_ARGS="$QEMU_ARGS -smp cores=4" # 4 cores -QEMU_ARGS="$QEMU_ARGS -serial stdio" # Use stdio for serial +QEMU_ARGS="$QEMU_ARGS -m 1G" # 2 GB of RAM +QEMU_ARGS="$QEMU_ARGS -smp cores=4" # 4 cores +QEMU_ARGS="$QEMU_ARGS -serial stdio" # Use stdio for serial +QEMU_ARGS="$QEMU_ARGS -monitor telnet::45454,server,nowait" # Use telnet for monitor if [ ! "$USE_DEBUG" -ne "0" ]; then -QEMU_ARGS="$QEMU_ARGS -d int" # Debug interrupts +QEMU_ARGS="$QEMU_ARGS -d int" # Debug interrupts fi -QEMU_ARGS="$QEMU_ARGS $DEBUG" # Enable debugging -QEMU_ARGS="$QEMU_ARGS $ACCELERATOR" # Enable acceleration -QEMU_ARGS="$QEMU_ARGS $DISPLAY_TYPE" # Enable display -QEMU_ARGS="$QEMU_ARGS -net nic,model=$NETWORK_DEVICE" # Add a network device -QEMU_ARGS="$QEMU_ARGS $PORT_FORWARDING" # Add port forwarding -QEMU_ARGS="$QEMU_ARGS -drive file=$IMAGE_PATH,format=raw" # Add the image as a drive -QEMU_ARGS="$QEMU_ARGS,if=ide,cache=directsync,id=disk0" # Configure the drive to be an ide drive with direct sync caching -QEMU_ARGS="$QEMU_ARGS -no-reboot -no-shutdown" # Don't reboot or shutdown on exit +QEMU_ARGS="$QEMU_ARGS $DEBUG" # Enable debugging +QEMU_ARGS="$QEMU_ARGS $ACCELERATOR" # Enable acceleration +QEMU_ARGS="$QEMU_ARGS $DISPLAY_TYPE" # Enable display +QEMU_ARGS="$QEMU_ARGS -net nic,model=$NETWORK_DEVICE" # Add a network device +QEMU_ARGS="$QEMU_ARGS $PORT_FORWARDING" # Add port forwarding +QEMU_ARGS="$QEMU_ARGS -drive file=$IMAGE_PATH,format=raw" # Add the image as a drive +QEMU_ARGS="$QEMU_ARGS,if=ide,cache=directsync,id=disk0" # Configure the drive to be an ide drive with direct sync caching +QEMU_ARGS="$QEMU_ARGS -no-reboot -no-shutdown" # Don't reboot or shutdown on exit # Run qemu msg "Running qemu with args: $QEMU_ARGS" From 1996c28c347990da09b7706d7052907520d8e2b9 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 12 Oct 2024 16:53:48 +1300 Subject: [PATCH 26/29] Virtual Memory Manager --- kernel/include/memory/memorymanagement.h | 2 + kernel/include/memory/physical.h | 25 ++- kernel/include/memory/virtual.h | 38 +++- kernel/src/kernel.cpp | 7 +- kernel/src/memory/memorymanagement.cpp | 4 + kernel/src/memory/physical.cpp | 256 +++++++++++++++++++---- kernel/src/memory/virtual.cpp | 223 +++++++++++++++++++- 7 files changed, 492 insertions(+), 63 deletions(-) diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index f61f06ca..2313fdbf 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -57,6 +57,8 @@ namespace MaxOS{ static void* to_lower_region(uintptr_t virtual_address); static void* to_io_region(uintptr_t physical_address); static void* to_dm_region(uintptr_t physical_address); + + static bool in_higher_region(uintptr_t virtual_address); }; } } diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index c4416f5b..fa7977dc 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -40,11 +40,6 @@ namespace MaxOS { } page_flags_t; - typedef enum PageBits { - WriteBit = (1 << 1), - UserBit = (1 << 3), - HugePageBit = (1 << 7), - } page_bits_t; // Struct for a page table entry typedef struct PageTableEntry { @@ -88,10 +83,14 @@ namespace MaxOS { bool m_initialized; - void clean_page_table(uint64_t* table); - - uint64_t* get_or_create_table(uint64_t* table, size_t index, size_t flags); + // Table Management + void create_table(pml_t* table, pml_t* next_table, size_t index); pte_t create_page_table_entry(uintptr_t address, size_t flags); + bool table_has_entry(pml_t* table, size_t index); + uint64_t* get_or_create_table(uint64_t* table, size_t index, size_t flags); + uint64_t* get_table_if_exists(uint64_t* table, size_t index); + + uint64_t* get_bitmap_address(); public: @@ -102,7 +101,10 @@ namespace MaxOS { // Vars static const uint32_t PAGE_SIZE = { 0x1000 }; // 4096 bytes - static const uint64_t PAGE_TABLE_OFFSET = { 0xFFFF000000000000 }; // The offset for the page table (before the kernel hihg half) + uint64_t get_memory_size(); + + // Pml4 + uint64_t* get_pml4_root_address(); // Frame Management void* allocate_frame(); @@ -114,12 +116,14 @@ namespace MaxOS { // Map virtual_address_t* map(virtual_address_t* virtual_address, size_t flags); virtual_address_t* map(physical_address_t* physical, virtual_address_t* virtual_address, size_t flags); + virtual_address_t* map(physical_address_t* physical, virtual_address_t* virtual_address, size_t flags, uint64_t* pml4_root); void map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags); void map_area(physical_address_t* physical_address_start, virtual_address_t* virtual_address_start, size_t length, size_t flags); void identity_map(physical_address_t* physical_address, size_t flags); void unmap(virtual_address_t* virtual_address); - + void unmap(virtual_address_t* virtual_address, uint64_t* pml4_root); + void unmap_area(virtual_address_t* virtual_address_start, size_t length); // Tools static size_t size_to_frames(size_t size); @@ -131,6 +135,7 @@ namespace MaxOS { bool is_multiboot_reserved(uint64_t address); static PhysicalMemoryManager* current_manager; + void clean_page_table(uint64_t* table); }; } diff --git a/kernel/include/memory/virtual.h b/kernel/include/memory/virtual.h index 37c86156..c6478dde 100644 --- a/kernel/include/memory/virtual.h +++ b/kernel/include/memory/virtual.h @@ -8,23 +8,59 @@ #include #include #include +#include namespace MaxOS { namespace memory { + typedef enum VirtualFlags { + // 0 - (1 << 8) are reserved for the page flags + Reserve = (1 << 9), + + } virtual_flags_t; + + typedef struct VirtualMemoryChunk{ + uintptr_t start_address; + size_t size; + size_t flags; + + } virtual_memory_chunk_t; + + typedef struct VirtualMemoryRegion{ + virtual_memory_chunk_t chunks[(PhysicalMemoryManager::PAGE_SIZE / sizeof(virtual_memory_chunk_t) - 1)]; + struct VirtualMemoryRegion* next; + + } __attribute__((packed)) virtual_memory_region_t; + class VirtualMemoryManager{ private: uint64_t * m_pml4_root_address; + uint64_t * m_pml4_root_physical_address; PhysicalMemoryManager* m_physical_memory_manager; + bool m_is_kernel; + + virtual_memory_region_t* m_first_region; + virtual_memory_region_t* m_current_region; + size_t m_current_chunk; + size_t m_next_available_address; + static const size_t s_chunks_per_page = (PhysicalMemoryManager::PAGE_SIZE / sizeof(virtual_memory_chunk_t) - 1); + static const size_t s_reserved_space = 0x138000000; + void new_region(); public: - VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager); + VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager, bool is_kernel); ~VirtualMemoryManager(); + void* allocate(size_t size, size_t flags); + void* allocate(uint64_t address, size_t size, size_t flags); + void free(void* address); + + size_t memory_used(); + }; } } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 8cad1135..7dac494d 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -128,7 +128,12 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) PhysicalMemoryManager pmm(addr + mbi_size, &multiboot, p4_table); _kprintf("-= Physical Memory Manager set up =-\n"); - // TODO: VMM + VirtualMemoryManager k_vmm(&pmm, true); + _kprintf("Freed test memory, vmm_used: %d\n", k_vmm.memory_used()); + + _kprintf("-= Virtual Memory Manager set up =-\n"); + + //TODO: Once this is all working a bit of clean up please AdvancedConfigurationAndPowerInterface acpi(&multiboot); _kprintf("-= ACPI set up =-\n"); diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index c626d45a..1792165f 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -196,6 +196,10 @@ void *MemoryManager::to_dm_region(uintptr_t physical_address) { } +bool MemoryManager::in_higher_region(uintptr_t virtual_address) { + return virtual_address & (1l << 62); +} + //Redefine the default object functions with memory orientated ones (defaults disabled in makefile) void* operator new(size_t size) throw(){ diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 67eef0d5..0d87d9e6 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -26,10 +26,10 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv current_manager = this; // Store the information about the bitmap - m_memory_size = multiboot->get_basic_meminfo()->mem_upper + 1024; + m_memory_size = (multiboot->get_basic_meminfo()->mem_upper + 1024) * 1000; m_bitmap_size = m_memory_size / PAGE_SIZE + 1; m_total_entries = m_bitmap_size / ROW_BITS + 1; - _kprintf("Mem Info: size = %dmb, bitmap size = %d, total entries = %d, page size = %db\n", (m_memory_size * 1024) / 1024 / 1024, m_bitmap_size, m_total_entries, PAGE_SIZE); + _kprintf("Mem Info: size = %dmb, bitmap size = %d, total entries = %d, page size = %db\n", ((m_memory_size / 1000) * 1024) / 1024 / 1024, m_bitmap_size, m_total_entries, PAGE_SIZE); // Get the mmap that stores the memory to use m_mmap_tag = multiboot->get_mmap(); @@ -121,7 +121,7 @@ size_t PhysicalMemoryManager::size_to_frames(size_t size) { size_t PhysicalMemoryManager::align_to_page(size_t size) { - return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + return ((size + PAGE_SIZE - 1) /PAGE_SIZE) * PAGE_SIZE; } size_t PhysicalMemoryManager::align_up_to_page(size_t size, size_t page_size) { @@ -154,8 +154,7 @@ void* PhysicalMemoryManager::allocate_frame() { } // Check if there are enough frames - if(m_used_frames >= m_bitmap_size) - return nullptr; + ASSERT(m_used_frames < m_bitmap_size, "No more frames available") // Loop through the bitmap for (uint16_t row = 0; row < m_total_entries; ++row) { @@ -256,45 +255,103 @@ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { } +void PhysicalMemoryManager::create_table(pml_t* table, pml_t* next_table, size_t index) { + // If the table is already created return + if(table_has_entry(table, index)) + return; + + // Create the table + uint64_t *new_table = (uint64_t *)allocate_frame(); + + // Set the table to the next table + table -> entries[index] = create_page_table_entry((uint64_t)new_table, Present | Write); + + // Clear the table + clean_page_table((uint64_t*)next_table); + +} + +uint64_t* PhysicalMemoryManager::get_or_create_table(uint64_t *table, size_t index, size_t flags) { + + // Address mask + uint64_t mask = 0xFFFFFFF000; + + // If the table is already created return it + if(table[index] & 0b1) + return (uint64_t *) MemoryManager::to_dm_region((uintptr_t) table[index] & mask); + + // Need to create the table + uint64_t *new_table = (uint64_t*)allocate_frame(); + table[index] = (uint64_t) new_table | flags; + + // Move the table to the higher half + new_table = (uint64_t*)MemoryManager::to_dm_region((uintptr_t) new_table); + + // Clear the table + clean_page_table(new_table); + + // All done + return new_table; +} + +bool PhysicalMemoryManager::table_has_entry(pml_t *table, size_t index) { + // Get the entry + pte_t* entry = &table -> entries[index]; + + // If the table is already created return it + return (entry -> present); + +} + +uint64_t *PhysicalMemoryManager::get_table_if_exists(uint64_t *table, size_t index) { + + // Address mask + uint64_t mask = 0xFFFFFFF000; + + // If the table is null return null + if(table == nullptr) + return nullptr; + + // Check if the table is present + if(table[index] & 0b1) + return (uint64_t *) MemoryManager::to_dm_region((uintptr_t) table[index] & mask); + +} -virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_address, virtual_address_t* address, size_t flags) { -#define SIGN_EXTENSION 0xFFFF000000000000 #define ENTRIES_TO_ADDRESS(pml4, pdpr, pd, pt)((pml4 << 39) | (pdpr << 30) | (pd << 21) | (pt << 12)) +virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_address, virtual_address_t* address, size_t flags) { - uint64_t* pml4_table = m_pml4_root_address; + // Base information + pml_t* pml4_table = (pml_t *)m_pml4_root_address; + size_t base_addr = 0xFFFF000000000000; - uint16_t pml4_e = PML4_GET_INDEX((uint64_t) address); - uint16_t pdpr_e = PML3_GET_INDEX((uint64_t) address); - uint16_t pd_e = PML2_GET_INDEX((uint64_t) address); - uint16_t pt_e = PML1_GET_INDEX((uint64_t) address); + // Get the indexes + uint16_t pml4_index = PML4_GET_INDEX((uint64_t) address); + uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) address); + uint16_t pd_index = PML2_GET_INDEX((uint64_t) address); + uint16_t pt_index = PML1_GET_INDEX((uint64_t) address); - uint64_t *pdpr_table =(uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l,510l,510l, (uint64_t) pml4_e)); - uint64_t *pd_table = (uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l,510l, (uint64_t) pml4_e, (uint64_t) pdpr_e)); - uint64_t *pt_table = (uint64_t *) (SIGN_EXTENSION | ENTRIES_TO_ADDRESS(510l, (uint64_t) pml4_e, (uint64_t) pdpr_e, (uint64_t) pd_e)); + // Get the tables + pml_t *pdpr_table =(pml_t *) (base_addr | ENTRIES_TO_ADDRESS(510l,510l,510l, (uint64_t) pml4_index)); + pml_t *pd_table = (pml_t *) (base_addr | ENTRIES_TO_ADDRESS(510l,510l, (uint64_t) pml4_index, (uint64_t) pdpr_index)); + pml_t *pt_table = (pml_t *) (base_addr | ENTRIES_TO_ADDRESS(510l, (uint64_t) pml4_index, (uint64_t) pdpr_index, (uint64_t) pd_index)); + // Create the tables + create_table(pml4_table, pdpr_table, pml4_index); + create_table(pdpr_table, pd_table, pdpr_index); + create_table(pd_table, pt_table, pd_index); - if( !(pml4_table[pml4_e] & 0b1) ) { - uint64_t *new_table = (uint64_t *)allocate_frame(); - pml4_table[pml4_e] = (uint64_t) new_table | Present | Write; - clean_page_table(pdpr_table); - } + // Get the entry + pte_t* pte = &pt_table -> entries[pt_index]; - if( !(pdpr_table[pdpr_e] & 0b1) ) { - uint64_t *new_table = (uint64_t *)allocate_frame(); - pdpr_table[pdpr_e] = (uint64_t) new_table | Present | Write; - clean_page_table(pd_table); - } + // If it already exists return the address + if(pte -> present) + return address; - if( !(pd_table[pd_e] & 0b01) ) { - uint64_t *new_table = (uint64_t *)allocate_frame(); - pd_table[pd_e] = (uint64_t) new_table | Present | Write; - clean_page_table(pt_table); - } + // Map the physical address to the virtual address + *pte = create_page_table_entry((uint64_t)physical_address, flags); - if( !(pt_table[pt_e] & 0b1)) { - pt_table[pt_e] = (uint64_t) physical_address | flags; - } // Flush the TLB asm volatile("invlpg (%0)" ::"r" (address) : "memory"); @@ -302,6 +359,43 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_addre return address; } +virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags, uint64_t *pml4_table) { + + // Get the indexes + uint16_t pml4_index = PML4_GET_INDEX((uint64_t) virtual_address); + uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) virtual_address); + uint16_t pd_index = PML2_GET_INDEX((uint64_t) virtual_address); + uint16_t pt_index = PML1_GET_INDEX((uint64_t) virtual_address); + + // If it is in a lower region then assume it is the user space + uint8_t is_user = MemoryManager::in_higher_region((uint64_t)virtual_address); + if(is_user) { + + // Change the flags to user + flags |= User; + is_user = User; + + } + + // Store the tables + uint64_t* pdpr_table = get_or_create_table(pml4_table, pml4_index, Present | Write | is_user); + uint64_t* pd_table = get_or_create_table(pdpr_table, pdpr_index, Present | Write | is_user); + uint64_t* pt_table = get_or_create_table(pd_table, pd_index, Present | Write | is_user); + + // If the page is already mapped return the address + if(pt_table[pt_index] & 0b1) + return virtual_address; + + // Map the physical address to the virtual address + pt_table[pt_index] = (uint64_t) physical | flags; + + // Flush the TLB + asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); + + return virtual_address; +} + + virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address, size_t flags) { // Create a new physical address for the frame @@ -342,8 +436,75 @@ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, s } void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { - ASSERT(false, "Not implemented!") - // TODO: Implement + + // Base information + pml_t* pml4_table = (pml_t *)m_pml4_root_address; + size_t base_addr = 0xFFFF000000000000; + + // Get the indexes + uint16_t pml4_index = PML4_GET_INDEX((uint64_t) virtual_address); + uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) virtual_address); + uint16_t pd_index = PML2_GET_INDEX((uint64_t) virtual_address); + uint16_t pt_index = PML1_GET_INDEX((uint64_t) virtual_address); + + // Get the tables + pml_t *pdpr_table =(pml_t *) (base_addr | ENTRIES_TO_ADDRESS(510l,510l,510l, (uint64_t) pml4_index)); + pml_t *pd_table = (pml_t *) (base_addr | ENTRIES_TO_ADDRESS(510l,510l, (uint64_t) pml4_index, (uint64_t) pdpr_index)); + uint64_t* pt_table = (uint64_t *) (base_addr | ENTRIES_TO_ADDRESS(510l, (uint64_t) pml4_index, (uint64_t) pdpr_index, (uint64_t) pd_index)); + + // Check if the entry is present + if(table_has_entry(pml4_table, pml4_index) && table_has_entry(pdpr_table, pdpr_index) && table_has_entry(pd_table, pd_index)) + return; + + // Check if the entry isn't present + if(!(pt_table[pt_index] & 0b1)) + return; + + // Unmap the entry + pt_table[pt_index] = 0x00l; + + // Flush the TLB + asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); +} + +void PhysicalMemoryManager::unmap(virtual_address_t *virtual_address, uint64_t *pml4_root) { + + // Get the indexes + uint16_t pml4_index = PML4_GET_INDEX((uint64_t) virtual_address); + uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) virtual_address); + uint16_t pd_index = PML2_GET_INDEX((uint64_t) virtual_address); + uint16_t pt_index = PML1_GET_INDEX((uint64_t) virtual_address); + + // Get the tables + uint64_t* pdpr_table = get_table_if_exists(pml4_root, pml4_index); + uint64_t* pd_table = get_table_if_exists(pdpr_table, pdpr_index); + uint64_t* pt_table = get_table_if_exists(pd_table, pd_index); + + // Check if the tables are present (if any are not then a pt entry will not be present) + if(pt_table == nullptr) + return; + + + // Check if the entry is present + if(!(pt_table[pt_index] & 0b1)) + return; + + // Unmap the entry + pt_table[pt_index] = 0x00l; + + // Flush the TLB + asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); + +} + +void PhysicalMemoryManager::unmap_area(virtual_address_t *virtual_address_start, size_t length) { + + // Get the size of the area + size_t size = size_to_frames(length); + + // Unmap the required frames + for (size_t i = 0; i < size; ++i) + unmap(virtual_address_start + (i * PAGE_SIZE)); } /** @@ -364,25 +525,17 @@ void PhysicalMemoryManager::clean_page_table(uint64_t *table) { } } -void clearBits(uint64_t *num, int start, int end) { - // Create a mask with 1s from start to end and 0s elsewhere - uint64_t mask = (~0ULL << start) ^ (~0ULL << (end + 1)); - - // Apply the mask to the number to clear the desired bits - *num &= ~mask; -} - pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) { pte_t page = (pte_t){ .present = 1, - .write = (flags & WriteBit) != 0, - .user = (flags & UserBit) != 0, + .write = (flags & Write) != 0, + .user = (flags & User) != 0, .write_through = (flags & (1 << 7)) != 0, .cache_disabled = 0, .accessed = 0, .dirty = 0, - .huge_page = (flags & HugePageBit) != 0, + .huge_page = (flags & HugePage) != 0, .global = 0, .available = 0, .physical_address = (uint64_t)address >> 12 @@ -421,12 +574,14 @@ bool PhysicalMemoryManager::is_anonymous_available(size_t address) { // Memory is not available return false; } + bool PhysicalMemoryManager::is_multiboot_reserved(uint64_t address) { //ASSERT(false, "Not implemented!") // TODO: Check if address is reserve by multiboot module return false; } + uint64_t *PhysicalMemoryManager::get_bitmap_address() { @@ -460,3 +615,12 @@ uint64_t *PhysicalMemoryManager::get_bitmap_address() { // Error no space for the bitmap ASSERT(false, "No space for the bitmap"); } + +uint64_t *PhysicalMemoryManager::get_pml4_root_address() { + return m_pml4_root_address; +} + +uint64_t PhysicalMemoryManager::get_memory_size() { + return m_memory_size; +} + diff --git a/kernel/src/memory/virtual.cpp b/kernel/src/memory/virtual.cpp index 06b5db63..57416d78 100644 --- a/kernel/src/memory/virtual.cpp +++ b/kernel/src/memory/virtual.cpp @@ -3,18 +3,69 @@ // #include +#include using namespace MaxOS::memory; +using namespace MaxOS::common; -VirtualMemoryManager::VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager) -: m_physical_memory_manager(physical_memory_manager) +VirtualMemoryManager::VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager, bool is_kernel) +: m_physical_memory_manager(physical_memory_manager), + m_is_kernel(is_kernel) { - //NOTE: See boot.s for the set up of paging + // If not the kernel, we need to allocate a new PML4 table + if(!m_is_kernel){ - // Map the physical memory to the higher half virtual memory + // Get a new pml4 table + m_pml4_root_physical_address = (uint64_t*)m_physical_memory_manager->allocate_frame(); + m_pml4_root_address = (uint64_t*)MemoryManager::to_dm_region((uint64_t)m_pml4_root_physical_address); + _kprintf("Allocated new PML4 table at: 0x%x\n", m_pml4_root_address); + + // Clear the table + m_physical_memory_manager -> clean_page_table(m_pml4_root_address); + + // Map the higher half of the kernel (p4 256 - 511) + for (size_t i = 256; i < 512; i++){ + + // Recursive Map the pml4 table (so that we can access the new pml4 table later on) + if(i == 510) { + m_pml4_root_address[i] = (uint64_t)m_pml4_root_physical_address | Present | Write; + continue; + } + + // Set the new pml4 table to the old (kernel) pml4 table + m_pml4_root_address[i] = m_physical_memory_manager->get_pml4_root_address()[i]; + + } + _kprintf("Mapped higher half of kernel\n"); + + + }else{ + m_pml4_root_address = m_physical_memory_manager->get_pml4_root_address(); + }; + + // Space to store VMM chunks + uint64_t vmm_space = PhysicalMemoryManager::align_to_page(MemoryManager::s_hh_direct_map_offset + m_physical_memory_manager->get_memory_size() + PhysicalMemoryManager::PAGE_SIZE); + m_first_region = (virtual_memory_region_t*)vmm_space; + m_current_region = m_first_region; + + // Allocate space for the vmm + void* vmm_space_physical = m_physical_memory_manager->allocate_frame(); + ASSERT(vmm_space_physical != nullptr, "Failed to allocate VMM space"); + m_physical_memory_manager->map(vmm_space_physical, (virtual_address_t*)vmm_space, Present | Write, m_pml4_root_address); + m_first_region->next = nullptr; + _kprintf("Allocated VMM: physical: 0x%x, virtual: 0x%x\n", vmm_space_physical, vmm_space); + + // Calculate the next available address + m_next_available_address = PhysicalMemoryManager::PAGE_SIZE; + if(m_is_kernel){ + + // Kernel needs to start at the higher half + m_next_available_address += vmm_space + s_reserved_space; + + } + _kprintf("Next available address: 0x%x\n", m_next_available_address); - // TODO: Virtual Memory Management (not just virtual addresses & physical addresses) } @@ -23,3 +74,165 @@ VirtualMemoryManager::~VirtualMemoryManager() { } + +void* VirtualMemoryManager::allocate(size_t size, size_t flags) { + return allocate(0, size, flags); +} + + + +void *VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags) { + /// This is used when we need to allocate at a specific address (ie reserving for mmap io devices) + + // Make sure allocating something + if(size == 0) + return nullptr; + + // If specific address is given + if(address != 0){ + + // Make sure isnt already allocated + if(address < m_next_available_address) + return nullptr; + + // Make sure its aligned + if(!PhysicalMemoryManager::check_aligned(address)) + return nullptr; + + } + + // Make sure the size is aligned + size = PhysicalMemoryManager::align_up_to_page(size, PhysicalMemoryManager::PAGE_SIZE); + + // Is there space in the current region + if(m_current_chunk >= s_chunks_per_page) + new_region(); + + // If we need to allocate at a specific address + if(address != 0){ + m_next_available_address = address; //TODO: Creates mem fragmentation - fix + } + + // Allocate the memory + virtual_memory_chunk_t* chunk = &m_current_region->chunks[m_current_chunk]; + chunk->size = size; + chunk->flags = flags; + chunk->start_address = m_next_available_address; + + // Update the next available address + m_next_available_address += size; + m_current_chunk++; + + // If just reserving the space don't map it + if(flags & Reserve) + return (void*)chunk->start_address; + + // Map the memory + size_t pages = PhysicalMemoryManager::size_to_frames(size); + for (size_t i = 0; i < pages; i++){ + + // Allocate a new frame + physical_address_t* frame = m_physical_memory_manager->allocate_frame(); + ASSERT(frame != nullptr, "Failed to allocate frame"); + + // Map the frame + m_physical_memory_manager->map(frame, (virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::PAGE_SIZE), Present | Write, m_pml4_root_address); + + } + + // Return the address + return (void*)chunk->start_address; +} + + +void VirtualMemoryManager::new_region() { + + // Space for the new region + physical_address_t* new_region_physical = m_physical_memory_manager->allocate_frame(); + ASSERT(new_region_physical != nullptr, "Failed to allocate new VMM region"); + + // Align the new region + virtual_memory_region_t* new_region = (virtual_memory_region_t*)PhysicalMemoryManager::align_to_page((uint64_t)m_current_region + PhysicalMemoryManager::PAGE_SIZE); + + // Map the new region + m_physical_memory_manager->map(new_region_physical, (virtual_address_t*)new_region, Present | Write, m_pml4_root_address); + new_region->next = nullptr; + + // Set the current region + m_current_region -> next = new_region; + m_current_chunk = 0; + m_current_region = new_region; + +} +void VirtualMemoryManager::free(void *address) { + + // Make sure freeing something + if(address == nullptr) + return; + + // Find the chunk + virtual_memory_region_t* region = m_first_region; + virtual_memory_chunk_t* chunk = nullptr; + while(region != nullptr){ + + // Loop through the chunks + for (size_t i = 0; i < s_chunks_per_page; i++){ + + // Check if the address is in the chunk + if(region->chunks[i].start_address == (uintptr_t)address){ + chunk = ®ion->chunks[i]; + break; + } + } + + // If the chunk was found + if(chunk != nullptr) + break; + + // Move to the next region + region = region->next; + } + + // Make sure the chunk was found + if(chunk == nullptr) + return; + + // Unmap the memory + size_t pages = PhysicalMemoryManager::size_to_frames(chunk->size); + for (size_t i = 0; i < pages; i++){ + + // Unmap the frame + m_physical_memory_manager->unmap((virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::PAGE_SIZE), m_pml4_root_address); + + } + + // Clear the chunk + chunk->size = 0; + chunk->flags = 0; + chunk->start_address = 0; + + // TODO: Some logic to use this space again +} +size_t VirtualMemoryManager::memory_used() { + + // Loop through all the regions and add up the size of the allocated chunks + size_t result = 0; + + // Iterate through the regions + virtual_memory_region_t *region = m_first_region; + while (region != nullptr) { + + // Loop through the chunks + for (size_t i = 0; i < s_chunks_per_page; i++) { + + // Check if the address is in the chunk + if (region->chunks[i].size != 0) + result += region->chunks[i].size; + } + + // Move to the next region + region = region->next; + } + + return result; +} From 75ba773faccdf3faeaa01268ef6bfb6fa18143e9 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sat, 12 Oct 2024 23:31:46 +1300 Subject: [PATCH 27/29] Kernel Malloc & Free --- kernel/include/memory/memorymanagement.h | 23 +++-- kernel/include/memory/physical.h | 3 +- kernel/include/memory/virtual.h | 3 +- kernel/src/hardwarecommunication/acpi.cpp | 2 +- kernel/src/hardwarecommunication/apic.cpp | 4 +- kernel/src/kernel.cpp | 76 +++++++--------- kernel/src/memory/memorymanagement.cpp | 105 +++++++++++++++------- kernel/src/memory/physical.cpp | 8 +- kernel/src/memory/virtual.cpp | 4 +- 9 files changed, 134 insertions(+), 94 deletions(-) diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index 2313fdbf..191304ee 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace MaxOS{ @@ -34,8 +34,13 @@ namespace MaxOS{ */ class MemoryManager{ - protected: - MemoryChunk* m_first_memory_chunk; + private: + MemoryChunk* m_first_memory_chunk; + MemoryChunk* m_last_memory_chunk; + + VirtualMemoryManager* m_virtual_memory_manager; + + MemoryChunk* expand_heap(size_t size); public: static MemoryManager* s_active_memory_manager; @@ -46,18 +51,26 @@ namespace MaxOS{ static const uint64_t s_higher_half_offset { s_higher_half_mem_offset + s_higher_half_mem_reserved}; static const uint64_t s_hh_direct_map_offset { s_higher_half_offset + PhysicalMemoryManager::PAGE_SIZE }; - MemoryManager(multiboot_tag_mmap* memory_map); + // Each chunk is aligned to 16 bytes + static const size_t s_chunk_alignment { 0x10 }; + + MemoryManager(VirtualMemoryManager* virtual_memory_manager); ~MemoryManager(); + // Memory Management void* malloc(size_t size); void free(void* pointer); + + // Utility Functions int memory_used(); + size_t align(size_t size); + + // Higher Half Memory Management static void* to_higher_region(uintptr_t physical_address); static void* to_lower_region(uintptr_t virtual_address); static void* to_io_region(uintptr_t physical_address); static void* to_dm_region(uintptr_t physical_address); - static bool in_higher_region(uintptr_t virtual_address); }; } diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index fa7977dc..01be8b58 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -13,7 +13,6 @@ namespace MaxOS { namespace memory { - #define VirtualPointer(addr) (void*)((uint64_t)(addr)) #define PMLX_GET_INDEX(ADDR, LEVEL) (((uint64_t)ADDR & ((uint64_t)0x1ff << (12 + LEVEL * 9))) >> (12 + LEVEL * 9)) @@ -134,7 +133,7 @@ namespace MaxOS { bool is_anonymous_available(size_t size); bool is_multiboot_reserved(uint64_t address); - static PhysicalMemoryManager* current_manager; + static PhysicalMemoryManager* s_current_manager; void clean_page_table(uint64_t* table); }; } diff --git a/kernel/include/memory/virtual.h b/kernel/include/memory/virtual.h index c6478dde..82107e4c 100644 --- a/kernel/include/memory/virtual.h +++ b/kernel/include/memory/virtual.h @@ -8,7 +8,6 @@ #include #include #include -#include namespace MaxOS { namespace memory { @@ -52,7 +51,7 @@ namespace MaxOS { void new_region(); public: - VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager, bool is_kernel); + VirtualMemoryManager(bool is_kernel); ~VirtualMemoryManager(); void* allocate(size_t size, size_t flags); diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index 3d348482..9e71cd2c 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -19,7 +19,7 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s m_rsdt = (RSDT*) rsdp->rsdt_address; // Map the RSDT - PhysicalMemoryManager::current_manager->map(m_rsdt, MemoryManager::to_io_region((uint64_t)m_rsdt), Present | Write); + PhysicalMemoryManager::s_current_manager->map(m_rsdt, MemoryManager::to_io_region((uint64_t)m_rsdt), Present | Write); m_rsdt = (RSDT*) MemoryManager::to_higher_region((uint64_t)m_rsdt); _kprintf("RSDT: physical: 0x%x, virtual: 0x%x\n", rsdp->rsdt_address, m_rsdt); diff --git a/kernel/src/hardwarecommunication/apic.cpp b/kernel/src/hardwarecommunication/apic.cpp index dc96a487..49e0f413 100644 --- a/kernel/src/hardwarecommunication/apic.cpp +++ b/kernel/src/hardwarecommunication/apic.cpp @@ -44,7 +44,7 @@ void LocalAPIC::init() { // Map the APIC base address to the higher half m_apic_base_high = (uint64_t)MemoryManager::to_io_region(m_apic_base); - PhysicalMemoryManager::current_manager->map(m_apic_base, m_apic_base_high, Write); + PhysicalMemoryManager::s_current_manager->map((physical_address_t*)m_apic_base, (virtual_address_t*)m_apic_base_high, Write | Present); _kprintf("APIC Base: phy=0x%x, virt=0x%x\n", m_apic_base, m_apic_base_high); } else { @@ -123,7 +123,7 @@ void IOAPIC::init() { // Map the IO APIC address to the higher half m_address_high = (uint64_t)MemoryManager::to_higher_region(m_address); _kprintf("IO APIC Address: phy=0x%x, virt=0x%x\n", m_address, m_address_high); - PhysicalMemoryManager::current_manager->map(VirtualPointer(m_address), VirtualPointer(m_address_high), Write);; + PhysicalMemoryManager::s_current_manager->map((physical_address_t*)m_address, (virtual_address_t*)m_address_high, Present | Write); // Get the IO APIC version and max redirection entry m_version = read(0x01); diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 7dac494d..7e86e3c2 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -118,9 +118,6 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("-= MaxOS booted =-\n"); - //GlobalDescriptorTable gdt; - //_kprintf("GDT set up\n"); - InterruptManager interrupts(0x20, 0); _kprintf("-= IDT set up =-\n"); @@ -128,37 +125,26 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) PhysicalMemoryManager pmm(addr + mbi_size, &multiboot, p4_table); _kprintf("-= Physical Memory Manager set up =-\n"); - VirtualMemoryManager k_vmm(&pmm, true); - _kprintf("Freed test memory, vmm_used: %d\n", k_vmm.memory_used()); - + VirtualMemoryManager vmm(true); _kprintf("-= Virtual Memory Manager set up =-\n"); - //TODO: Once this is all working a bit of clean up please - - AdvancedConfigurationAndPowerInterface acpi(&multiboot); - _kprintf("-= ACPI set up =-\n"); - - AdvancedProgrammableInterruptController apic(&acpi); - _kprintf("-= APIC set up =-\n"); + // Init memory management + MemoryManager memoryManager(&vmm); + void* test = memoryManager.malloc(100); + memoryManager.free(test); - interrupts.activate(); - _kprintf("-= IDT activated =-\n"); + _kprintf("-= Memory Manager set up =-\n"); // TODO: 64 bit architecture rewrite - // - Fix Paging - // - Finish ACPI - // - Memory Allocation - // - Convert old codebase + // - APIC and ACPI + // - Convert old codebase to higher half _kprintf("-= KERNEL DONE =-\n"); while (true) { - //TODO: This causes a Double Fault and then infinte General Protection Faults system::CPU::halt(); } - // Init memory management - MemoryManager memoryManager(multiboot.get_mmap()); - // TODO: Alot needs to be page mapped and higher halfed - + // Now entered the gui space + _kprintf("__ Basic System Setup [DONE] __\n"); // Initialise the VESA Driver VideoElectronicsStandardsAssociation vesa(multiboot.get_framebuffer()); @@ -196,23 +182,19 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) ConsoleStream systemSetupHeaderStream(&systemSetupHeader); systemSetupHeaderStream << "Setting up system"; - //Setup GDT - // TODO: GlobalDescriptorTable gdt; - cout << "-- Set Up GDT\n"; - systemSetupHeaderStream << "."; - - // Print that the memory has been set up - cout << "-- Set Up Memory Management\n"; - systemSetupHeaderStream << "."; + // Stuff done earlier + cout << "-- Set Up Paging\n"; + cout << "-- Set Up Interrupt Manager\n"; + cout << "-- Set Up Physical Memory Management\n"; + cout << "-- Set Up Virtual Memory Management\n"; + cout << "-- Set Up Memory Management (Kernel)\n"; + cout << "-- Set Up VESA Driver\n"; + systemSetupHeaderStream << "......"; ThreadManager threadManager; cout << "-- Set Up Thread Management\n"; systemSetupHeaderStream << "."; - //TODO: InterruptManager interrupts(0x20, &gdt, &threadManager, &cout); //Instantiate the function - cout << "-- Set Up Interrupts\n"; - systemSetupHeaderStream << "."; - SyscallHandler syscalls(&interrupts, 0x80); //Instantiate the function cout << "-- Set Up System Calls\n"; systemSetupHeaderStream << "."; @@ -227,7 +209,17 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) DriverManager driverManager; - //Keyboard + //TODO: ACPI + AdvancedConfigurationAndPowerInterface acpi(&multiboot); + cout << "-- Set Up ACPI\n"; + deviceSetupHeaderStream << "."; + + //TODO: APIC + AdvancedProgrammableInterruptController apic(&acpi); + cout << "-- Set Up APIC\n"; + deviceSetupHeaderStream << "."; + + // Keyboard KeyboardDriver keyboard(&interrupts); KeyboardInterpreterEN_US keyboardInterpreter; keyboard.connect_input_stream_event_handler(&keyboardInterpreter); @@ -235,22 +227,22 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) cout << "-- Set Up Keyboard\n"; deviceSetupHeaderStream << "."; - //Mouse + // Mouse MouseDriver mouse(&interrupts); driverManager.add_driver(&mouse); cout << "-- Set Up Mouse\n"; deviceSetupHeaderStream << "."; - //Clock + // Clock Clock kernelClock(&interrupts, 1); driverManager.add_driver(&kernelClock); cout << "-- Set Up Clock\n"; deviceSetupHeaderStream << "."; - //Driver Selectors + // Driver Selectors Vector driverSelectors; - //Make the stream on the side for the PCI + // Make the stream on the side for the PCI ConsoleArea pciConsoleArea(&console, console.width() - 45, areaStart+1, 45, console.height()/2, ConsoleColour::DarkGrey, ConsoleColour::Black); ConsoleStream pciConsoleStream(&pciConsoleArea); console.put_string(console.width() - 45, areaStart, " PCI Devices ", ConsoleColour::LightGrey, ConsoleColour::Black); @@ -329,7 +321,7 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) cout << "\n"; activationHeaderStream << "[ DONE ]"; - // Make the network setup stream + // Make the network setup stream (TODO: Move to user space) ConsoleArea networkSetupHeader(&console, 0, cout.m_cursor_y, console.width(), 1, ConsoleColour::LightGrey, ConsoleColour::Black); ConsoleStream networkSetupHeaderStream(&networkSetupHeader); networkSetupHeaderStream << "Setting up network"; diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index 1792165f..c0759c0f 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -3,47 +3,31 @@ // #include +#include using namespace MaxOS; using namespace MaxOS::memory; +using namespace MaxOS::common; MemoryManager* MemoryManager::s_active_memory_manager = 0; -MemoryManager::MemoryManager(multiboot_tag_mmap* memory_map) +MemoryManager::MemoryManager(VirtualMemoryManager* vmm) +: m_virtual_memory_manager(vmm) { - - size_t heap = 0; - size_t size = 0; - - // Find the available memory - for (multiboot_memory_map_t* mmap = memory_map->entries; (unsigned long)mmap < (unsigned long)memory_map + memory_map->size; - mmap = (multiboot_memory_map_t*)((unsigned long)mmap + memory_map->entry_size)) { - - // If the memory is available then use it - if(mmap -> type == MULTIBOOT_MEMORY_AVAILABLE){ - heap = mmap -> addr; - size = mmap -> len; - } - } - - // Add a 10MB offset to the heap - heap += 0x1000000; - + // This is the memory managers s_active_memory_manager = this; - //Prevent wiring outside the area that is allowed to write - if(size < sizeof(MemoryChunk)){ + // Get the first chunk of memory + this -> m_first_memory_chunk = (MemoryChunk*)m_virtual_memory_manager->allocate(PhysicalMemoryManager::PAGE_SIZE + sizeof(MemoryChunk), 0); + m_first_memory_chunk-> allocated = false; + m_first_memory_chunk-> prev = 0; + m_first_memory_chunk-> next = 0; + m_first_memory_chunk-> size = PhysicalMemoryManager::PAGE_SIZE - sizeof(MemoryChunk); - this ->m_first_memory_chunk = 0; + // Set the last chunk to the first chunk + m_last_memory_chunk = m_first_memory_chunk; - }else{ - - this ->m_first_memory_chunk = (MemoryChunk*)heap; - m_first_memory_chunk-> allocated = false; - m_first_memory_chunk-> prev = 0; - m_first_memory_chunk-> next = 0; - m_first_memory_chunk-> size = size - sizeof(MemoryChunk); - } + _kprintf("First memory chunk: 0x%x\n", m_first_memory_chunk); } MemoryManager::~MemoryManager() { @@ -61,23 +45,29 @@ void* MemoryManager::malloc(size_t size) { MemoryChunk* result = 0; + // Don't allocate a block of size 0 + if(size == 0) + return 0; + + // Size must include the size of the chunk and be aligned + size = align(size + sizeof(MemoryChunk)); + // Find the next free chunk that is big enough for (MemoryChunk* chunk = m_first_memory_chunk; chunk != 0 && result == 0; chunk = chunk->next) { if(chunk -> size > size && !chunk -> allocated) result = chunk; } - // If there is no free chunk then return 0 + // If there is no free chunk then expand the heap if(result == 0) - return 0; + result = expand_heap(size); - // If there is space to split the chunk + // If there is not enough space to create a new chunk then just allocate the current chunk if(result -> size < size + sizeof(MemoryChunk) + 1) { result->allocated = true; return (void *)(((size_t)result) + sizeof(MemoryChunk)); } - // Create a new chunk after the current one MemoryChunk* temp = (MemoryChunk*)((size_t)result + sizeof(MemoryChunk) + size); @@ -96,6 +86,10 @@ void* MemoryManager::malloc(size_t size) { result -> allocated = true; result->next = temp; + // Update the last memory chunk if necessary + if(result == m_last_memory_chunk) + m_last_memory_chunk = temp; + return (void*)(((size_t)result) + sizeof(MemoryChunk)); } @@ -108,6 +102,14 @@ void* MemoryManager::malloc(size_t size) { void MemoryManager::free(void *pointer) { + // If nothing to free then return + if(pointer == 0) + return; + + // If block is not in the memory manager's range then return + if((uint64_t ) pointer < (uint64_t ) m_first_memory_chunk || (uint64_t ) pointer > (uint64_t ) m_last_memory_chunk) + return; + // Create a new free chunk MemoryChunk* chunk = (MemoryChunk*)((size_t)pointer - sizeof(MemoryChunk)); chunk -> allocated = false; @@ -142,6 +144,33 @@ void MemoryManager::free(void *pointer) { } } +MemoryChunk *MemoryManager::expand_heap(size_t size) { + + // Create a new chunk of memory + MemoryChunk* chunk = (MemoryChunk*)m_virtual_memory_manager->allocate(size, Present | Write); + + // If the chunk is null then there is no more memory + ASSERT(chunk != 0, "Out of memory - kernel cannot allocate any more memory"); + + // Set the chunk's properties + chunk -> allocated = false; + chunk -> size = size; + chunk -> next = 0; + + // Insert the chunk into the linked list + m_last_memory_chunk -> next = chunk; + chunk -> prev = m_last_memory_chunk; + m_last_memory_chunk = chunk; + + // If it is possible to move to merge the new chunk with the previous chunk then do so (note: this happens if the previous chunk is free but cant contain the size required) + if(!chunk -> prev -> allocated) + free((void*)((size_t)chunk + sizeof(MemoryChunk))); + + return chunk; + +} + + /** * @brief Returns the amount of memory used * @return The amount of memory used @@ -157,6 +186,13 @@ int MemoryManager::memory_used() { return result; } + + +size_t MemoryManager::align(size_t size) { + return (size / s_chunk_alignment + 1) * s_chunk_alignment; +} + + void* MemoryManager::to_higher_region(uintptr_t physical_address) { // If it's in the lower half then add the offset @@ -200,6 +236,7 @@ bool MemoryManager::in_higher_region(uintptr_t virtual_address) { return virtual_address & (1l << 62); } + //Redefine the default object functions with memory orientated ones (defaults disabled in makefile) void* operator new(size_t size) throw(){ diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 0d87d9e6..053e6833 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -9,7 +9,7 @@ using namespace MaxOS::memory; using namespace MaxOS::system; extern uint64_t p4_table[]; -PhysicalMemoryManager* PhysicalMemoryManager::current_manager = nullptr; +PhysicalMemoryManager* PhysicalMemoryManager::s_current_manager = nullptr; extern uint64_t _kernel_end; extern uint64_t _kernel_size; extern uint64_t _kernel_physical_end; @@ -18,13 +18,13 @@ extern uint64_t multiboot_tag_start; MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserved, Multiboot* multiboot, uint64_t pml4_root[512]) { + // Set the current manager + s_current_manager = this; + // SEE boot.s FOR SETUP OF PAGING m_pml4_root = (pte_t *)pml4_root; m_pml4_root_address = pml4_root; - // Set the current manager - current_manager = this; - // Store the information about the bitmap m_memory_size = (multiboot->get_basic_meminfo()->mem_upper + 1024) * 1000; m_bitmap_size = m_memory_size / PAGE_SIZE + 1; diff --git a/kernel/src/memory/virtual.cpp b/kernel/src/memory/virtual.cpp index 57416d78..36083a81 100644 --- a/kernel/src/memory/virtual.cpp +++ b/kernel/src/memory/virtual.cpp @@ -8,8 +8,8 @@ using namespace MaxOS::memory; using namespace MaxOS::common; -VirtualMemoryManager::VirtualMemoryManager(PhysicalMemoryManager* physical_memory_manager, bool is_kernel) -: m_physical_memory_manager(physical_memory_manager), +VirtualMemoryManager::VirtualMemoryManager(bool is_kernel) +: m_physical_memory_manager(PhysicalMemoryManager::s_current_manager), m_is_kernel(is_kernel) { From 574868b67c18fbe89e7449c10383c1ec42870475 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sun, 13 Oct 2024 10:27:49 +1300 Subject: [PATCH 28/29] Doxy Gen Documentation --- README.md | 2 +- docs/Styles/Pre Merge Checklist | 5 + kernel/include/memory/memorymanagement.h | 2 +- kernel/include/memory/physical.h | 4 +- kernel/include/memory/virtual.h | 4 +- kernel/src/asm/loader.s | 10 +- kernel/src/drivers/video/vesa.cpp | 25 ++- kernel/src/hardwarecommunication/acpi.cpp | 2 +- kernel/src/kernel.cpp | 18 +- kernel/src/memory/memorymanagement.cpp | 42 ++++- kernel/src/memory/physical.cpp | 208 ++++++++++++++++++---- kernel/src/memory/virtual.cpp | 42 +++-- 12 files changed, 294 insertions(+), 70 deletions(-) create mode 100644 docs/Styles/Pre Merge Checklist diff --git a/README.md b/README.md index 9fe8b564..0371d9b5 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ Distributed under the BSD 3-Clause License. See `LICENSE` for more information. [issues-url]: https://github.com/maxtyson123/MaxOS/issues [built-shield]: https://img.shields.io/github/actions/workflow/status/maxtyson123/MaxOS/max-os.yml?style=for-the-badge [built-url]: https://github.com/maxtyson123/MaxOS/actions/workflows/max-os.yml -[loc-shield]: https://img.shields.io/tokei/lines/github/maxtyson123/MaxOS?style=for-the-badge +[loc-shield]: https://tokei.rs/b1/github/maxtyson123/MaxOS?style=for-the-badge [loc-url]: https://github.com/maxtyson123/MaxOS [wakatime-shield]: https://wakatime.com/badge/github/maxtyson123/MaxOS.svg?style=for-the-badge [wakatime-url]: https://wakatime.com/badge/github/maxtyson123/MaxOS \ No newline at end of file diff --git a/docs/Styles/Pre Merge Checklist b/docs/Styles/Pre Merge Checklist new file mode 100644 index 00000000..420322bc --- /dev/null +++ b/docs/Styles/Pre Merge Checklist @@ -0,0 +1,5 @@ +- Are to dos completed? +- Are all the files in the correct location? +- Kprintf used where necessary - no testing information? +- Tested to ensure that the changes work? +- Doxygen comments added? \ No newline at end of file diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index 191304ee..6e5b5ab9 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -49,7 +49,7 @@ namespace MaxOS{ static const uint64_t s_higher_half_mem_offset { 0xFFFF800000000000 }; static const uint64_t s_higher_half_mem_reserved { 0x280000000 }; static const uint64_t s_higher_half_offset { s_higher_half_mem_offset + s_higher_half_mem_reserved}; - static const uint64_t s_hh_direct_map_offset { s_higher_half_offset + PhysicalMemoryManager::PAGE_SIZE }; + static const uint64_t s_hh_direct_map_offset { s_higher_half_offset + PhysicalMemoryManager::s_page_size }; // Each chunk is aligned to 16 bytes static const size_t s_chunk_alignment { 0x10 }; diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h index 01be8b58..ba28553f 100644 --- a/kernel/include/memory/physical.h +++ b/kernel/include/memory/physical.h @@ -99,7 +99,7 @@ namespace MaxOS { // Vars - static const uint32_t PAGE_SIZE = { 0x1000 }; // 4096 bytes + static const uint32_t s_page_size = { 0x1000 }; // 4096 bytes uint64_t get_memory_size(); // Pml4 @@ -127,7 +127,7 @@ namespace MaxOS { // Tools static size_t size_to_frames(size_t size); static size_t align_to_page(size_t size); - static size_t align_up_to_page(size_t size, size_t page_size); + static size_t align_up_to_page(size_t size, size_t s_page_size); static bool check_aligned(size_t size); bool is_mapped(uintptr_t physical_address, uintptr_t virtual_address); bool is_anonymous_available(size_t size); diff --git a/kernel/include/memory/virtual.h b/kernel/include/memory/virtual.h index 82107e4c..6de8d576 100644 --- a/kernel/include/memory/virtual.h +++ b/kernel/include/memory/virtual.h @@ -27,7 +27,7 @@ namespace MaxOS { } virtual_memory_chunk_t; typedef struct VirtualMemoryRegion{ - virtual_memory_chunk_t chunks[(PhysicalMemoryManager::PAGE_SIZE / sizeof(virtual_memory_chunk_t) - 1)]; + virtual_memory_chunk_t chunks[(PhysicalMemoryManager::s_page_size / sizeof(virtual_memory_chunk_t) - 1)]; struct VirtualMemoryRegion* next; } __attribute__((packed)) virtual_memory_region_t; @@ -45,7 +45,7 @@ namespace MaxOS { size_t m_current_chunk; size_t m_next_available_address; - static const size_t s_chunks_per_page = (PhysicalMemoryManager::PAGE_SIZE / sizeof(virtual_memory_chunk_t) - 1); + static const size_t s_chunks_per_page = (PhysicalMemoryManager::s_page_size / sizeof(virtual_memory_chunk_t) - 1); static const size_t s_reserved_space = 0x138000000; void new_region(); diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s index a3c97b94..beb2cd14 100644 --- a/kernel/src/asm/loader.s +++ b/kernel/src/asm/loader.s @@ -31,12 +31,12 @@ endstruc %define HUGEPAGE_BIT 0b10000000 %if SMALL_PAGES == 1 -%define PAGE_SIZE 0x1000 ; PAGE_SIZE is 4k +%define s_page_size 0x1000 ; s_page_size is 4k %define PAGE_TABLE_ENTRY WRITE_BIT | PRESENT_BIT ;PAGE_TABLE_ENTRY for 4k pages, huge page bit is left to 0 %define LOOP_LIMIT 1024 %define PD_LOOP_LIMIT 2 %elif SMALL_PAGES == 0 -%define PAGE_SIZE 0x200000 +%define s_page_size 0x200000 %define PAGE_TABLE_ENTRY HUGEPAGE_BIT | WRITE_BIT | PRESENT_BIT ;PAGE_TABLE (pd table) entry for 2M pages, huge page bit is set. %define LOOP_LIMIT 512 %endif @@ -108,7 +108,7 @@ start: mov ecx, 0 ; Loop counter .map_p2_table: - mov eax, PAGE_SIZE ; Size of the page + mov eax, s_page_size ; Size of the page mul ecx ; Multiply by counter or eax, PAGE_TABLE_ENTRY ; We set: huge page bit (if on 2M pages), writable and present @@ -210,7 +210,7 @@ read_multiboot: mov rbx, [(rax + multiboot_tag_framebuffer.framebuffer_addr)] or rbx, PAGE_TABLE_ENTRY mov qword [(p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 488], rbx - add rbx, PAGE_SIZE + add rbx, s_page_size or rbx, PAGE_TABLE_ENTRY mov qword [(p2_table - KERNEL_VIRTUAL_ADDR) + 8 * 489], rbx %else @@ -222,7 +222,7 @@ read_multiboot: .map_fb: or rbx, PAGE_TABLE_ENTRY mov qword [(fbb_pt_tables) + 8 * rcx], rbx - add rbx, PAGE_SIZE + add rbx, s_page_size inc rcx cmp rcx, 512 jne .map_fb diff --git a/kernel/src/drivers/video/vesa.cpp b/kernel/src/drivers/video/vesa.cpp index 4aeafe67..5f4ac5f1 100644 --- a/kernel/src/drivers/video/vesa.cpp +++ b/kernel/src/drivers/video/vesa.cpp @@ -3,26 +3,41 @@ // #include +#include using namespace MaxOS; using namespace MaxOS::drivers; using namespace MaxOS::drivers::video; using namespace MaxOS::memory; using namespace MaxOS::system; +using namespace MaxOS::common; VideoElectronicsStandardsAssociation::VideoElectronicsStandardsAssociation(multiboot_tag_framebuffer* framebuffer_info) -: VideoDriver(), - m_framebuffer_info(framebuffer_info), - m_framebuffer_address((uint64_t *)framebuffer_info->common.framebuffer_addr), - m_bpp(framebuffer_info->common.framebuffer_bpp), - m_pitch(framebuffer_info->common.framebuffer_pitch) +: VideoDriver() { + // Get the framebuffer info + m_framebuffer_info = (multiboot_tag_framebuffer*)MemoryManager::to_dm_region((uint64_t)framebuffer_info); + _kprintf("Framebuffer info: physical = 0x%x, virtual = 0x%x\n", framebuffer_info, m_framebuffer_info); + + // Set the framebuffer address, bpp and pitch + m_bpp = m_framebuffer_info->common.framebuffer_bpp; + m_pitch = m_framebuffer_info->common.framebuffer_pitch; + + // Get the framebuffer address + m_framebuffer_address = (uint64_t*)MemoryManager::to_dm_region((uint64_t)m_framebuffer_info->common.framebuffer_addr); + _kprintf("Framebuffer address: physical = 0x%x, virtual = 0x%x\n", m_framebuffer_info->common.framebuffer_addr, m_framebuffer_address); + } VideoElectronicsStandardsAssociation::~VideoElectronicsStandardsAssociation(){ } +/** + * @brief Initializes the VESA driver + * + * @return True if the driver was initialized successfully, false otherwise + */ bool VideoElectronicsStandardsAssociation::init() { //Multiboot inits this for us diff --git a/kernel/src/hardwarecommunication/acpi.cpp b/kernel/src/hardwarecommunication/acpi.cpp index 9e71cd2c..5532d110 100644 --- a/kernel/src/hardwarecommunication/acpi.cpp +++ b/kernel/src/hardwarecommunication/acpi.cpp @@ -26,7 +26,7 @@ AdvancedConfigurationAndPowerInterface::AdvancedConfigurationAndPowerInterface(s // Load the header m_header = &m_rsdt->header; - if((m_header->length / PhysicalMemoryManager::PAGE_SIZE + 1) > 1) { + if((m_header->length / PhysicalMemoryManager::s_page_size + 1) > 1) { ASSERT(false, "RSDT is too big, need to map more pages!") } diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 7e86e3c2..a0de994c 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -135,16 +135,18 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("-= Memory Manager set up =-\n"); - // TODO: 64 bit architecture rewrite - // - APIC and ACPI - // - Convert old codebase to higher half - _kprintf("-= KERNEL DONE =-\n"); + // Now entered the gui space + _kprintf("__ Basic System Setup [DONE] __\n"); + while (true) { - system::CPU::halt(); + system::CPU::halt(); } - // Now entered the gui space - _kprintf("__ Basic System Setup [DONE] __\n"); + + // TODO: 64 bit architecture rewrite + // - Convert old codebase to higher half + // - APIC and ACPI + // - Rewrite read me // Initialise the VESA Driver VideoElectronicsStandardsAssociation vesa(multiboot.get_framebuffer()); @@ -158,6 +160,8 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) console.clear(); console.print_logo(); + + // Create a stream for the console ConsoleArea mainConsoleArea(&console, 0, 1, console.width(), console.height(), ConsoleColour::DarkGrey, ConsoleColour::Black); ConsoleStream cout(&mainConsoleArea); diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index c0759c0f..54f198dd 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -18,11 +18,11 @@ MemoryManager::MemoryManager(VirtualMemoryManager* vmm) s_active_memory_manager = this; // Get the first chunk of memory - this -> m_first_memory_chunk = (MemoryChunk*)m_virtual_memory_manager->allocate(PhysicalMemoryManager::PAGE_SIZE + sizeof(MemoryChunk), 0); + this -> m_first_memory_chunk = (MemoryChunk*)m_virtual_memory_manager->allocate(PhysicalMemoryManager::s_page_size + sizeof(MemoryChunk), 0); m_first_memory_chunk-> allocated = false; m_first_memory_chunk-> prev = 0; m_first_memory_chunk-> next = 0; - m_first_memory_chunk-> size = PhysicalMemoryManager::PAGE_SIZE - sizeof(MemoryChunk); + m_first_memory_chunk-> size = PhysicalMemoryManager::s_page_size - sizeof(MemoryChunk); // Set the last chunk to the first chunk m_last_memory_chunk = m_first_memory_chunk; @@ -144,6 +144,11 @@ void MemoryManager::free(void *pointer) { } } +/** + * @brief Expands the heap by a given size + * @param size The size to expand the heap by + * @return The new chunk of memory + */ MemoryChunk *MemoryManager::expand_heap(size_t size) { // Create a new chunk of memory @@ -187,12 +192,20 @@ int MemoryManager::memory_used() { return result; } - +/** + * @brief Aligns the size to the chunk alignment + * @param size The size to align + * @return The aligned size + */ size_t MemoryManager::align(size_t size) { return (size / s_chunk_alignment + 1) * s_chunk_alignment; } - +/** + * @brief Converts a physical address to a higher region address if it is in the lower region using the higher half kernel offset + * @param physical_address The physical address + * @return The higher region address + */ void* MemoryManager::to_higher_region(uintptr_t physical_address) { // If it's in the lower half then add the offset @@ -204,6 +217,11 @@ void* MemoryManager::to_higher_region(uintptr_t physical_address) { } +/** + * @brief Converts a virtual address to a lower region address if it is in the higher region using the higher half kernel offset + * @param virtual_address The virtual address + * @return The lower region address + */ void *MemoryManager::to_lower_region(uintptr_t virtual_address) { // If it's in the lower half then add the offset if(virtual_address > s_higher_half_kernel_offset) @@ -213,6 +231,11 @@ void *MemoryManager::to_lower_region(uintptr_t virtual_address) { return (void*)virtual_address; } +/** + * @brief Converts a physical address to an IO region address if it is in the lower region using the higher half memory offset + * @param physical_address The physical address + * @return The IO region address + */ void *MemoryManager::to_io_region(uintptr_t physical_address) { if(physical_address < s_higher_half_mem_offset) @@ -222,6 +245,12 @@ void *MemoryManager::to_io_region(uintptr_t physical_address) { return (void*)physical_address; } + +/** + * @brief Converts a physical address to a direct map region address if it is in the lower region using the higher half direct map offset + * @param physical_address The physical address + * @return The direct map region address + */ void *MemoryManager::to_dm_region(uintptr_t physical_address) { if(physical_address < s_higher_half_offset) @@ -232,6 +261,11 @@ void *MemoryManager::to_dm_region(uintptr_t physical_address) { } +/** + * @brief Checks if a virtual address is in the higher region + * @param virtual_address The virtual address + * @return True if the address is in the higher region, false otherwise + */ bool MemoryManager::in_higher_region(uintptr_t virtual_address) { return virtual_address & (1l << 62); } diff --git a/kernel/src/memory/physical.cpp b/kernel/src/memory/physical.cpp index 053e6833..0bcd4e08 100644 --- a/kernel/src/memory/physical.cpp +++ b/kernel/src/memory/physical.cpp @@ -27,9 +27,9 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Store the information about the bitmap m_memory_size = (multiboot->get_basic_meminfo()->mem_upper + 1024) * 1000; - m_bitmap_size = m_memory_size / PAGE_SIZE + 1; + m_bitmap_size = m_memory_size / s_page_size + 1; m_total_entries = m_bitmap_size / ROW_BITS + 1; - _kprintf("Mem Info: size = %dmb, bitmap size = %d, total entries = %d, page size = %db\n", ((m_memory_size / 1000) * 1024) / 1024 / 1024, m_bitmap_size, m_total_entries, PAGE_SIZE); + _kprintf("Mem Info: size = %dmb, bitmap size = %d, total entries = %d, page size = %db\n", ((m_memory_size / 1000) * 1024) / 1024 / 1024, m_bitmap_size, m_total_entries, s_page_size); // Get the mmap that stores the memory to use m_mmap_tag = multiboot->get_mmap(); @@ -46,8 +46,8 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv // Kernel Memory (anonymous memory to the next page) _kprintf("Kernel Memory: kernel_end = 0x%x, kernel_size = 0x%x, kernel_physical_end = 0x%x\n", &_kernel_end, &_kernel_size, &_kernel_physical_end); - m_anonymous_memory_physical_address = (uint64_t)align_up_to_page((size_t)(&_kernel_physical_end + PAGE_SIZE), PAGE_SIZE); - m_anonymous_memory_virtual_address = (uint64_t)align_up_to_page((size_t)(&_kernel_end + PAGE_SIZE), PAGE_SIZE); + m_anonymous_memory_physical_address = (uint64_t)align_up_to_page((size_t)(&_kernel_physical_end + s_page_size), s_page_size); + m_anonymous_memory_virtual_address = (uint64_t)align_up_to_page((size_t)(&_kernel_end + s_page_size), s_page_size); _kprintf("Anonymous Memory: physical = 0x%x, virtual = 0x%x\n", m_anonymous_memory_physical_address, m_anonymous_memory_virtual_address); // Map the physical memory into the virtual memory @@ -57,13 +57,13 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv while (physical_address < mem_end) { map((physical_address_t *)physical_address, (virtual_address_t *)virtual_address, Present | Write); - physical_address += PAGE_SIZE; - virtual_address += PAGE_SIZE; + physical_address += s_page_size; + virtual_address += s_page_size; } _kprintf("Mapped: physical = 0x%x-0x%x, virtual = 0x%x-0x%x\n", 0, physical_address, MemoryManager::s_hh_direct_map_offset, virtual_address); // TODO: FAILS WHEN TRYING WITH LIKE 2Gb Mem // Get the bitmap & clear it - m_anonymous_memory_physical_address += PAGE_SIZE; + m_anonymous_memory_physical_address += s_page_size; m_bit_map = get_bitmap_address(); for (uint32_t i = 0; i < m_total_entries; ++i) @@ -71,8 +71,8 @@ MaxOS::memory::PhysicalMemoryManager::PhysicalMemoryManager(unsigned long reserv _kprintf("Bitmap: location = 0x%x - 0x%x\n", m_bit_map, m_bit_map + m_bitmap_size / 8); // Calculate how much space the kernel takes up - uint32_t kernel_entries = (m_anonymous_memory_physical_address / PAGE_SIZE) + 1; - if ((((uint32_t)(m_anonymous_memory_physical_address)) % PAGE_SIZE) != 0) { + uint32_t kernel_entries = (m_anonymous_memory_physical_address / s_page_size) + 1; + if ((((uint32_t)(m_anonymous_memory_physical_address)) % s_page_size) != 0) { // If the kernel takes up more then a whole page(s) kernel_entries += 1; } @@ -115,24 +115,47 @@ PhysicalMemoryManager::~PhysicalMemoryManager() { } +/** + * @brief Converts a size to the number of frames + * @param size The size to convert + * @return The number of frames + */ size_t PhysicalMemoryManager::size_to_frames(size_t size) { - return align_to_page(size) / PAGE_SIZE; + return align_to_page(size) / s_page_size; } - +/** + * @brief Aligns a size to the page size + * @param size The size to align + * @return The aligned size + */ size_t PhysicalMemoryManager::align_to_page(size_t size) { - return ((size + PAGE_SIZE - 1) /PAGE_SIZE) * PAGE_SIZE; + return ((size + s_page_size - 1) /s_page_size) * s_page_size; } +/** + * @brief Aligns a size up to the page size + * @param size The size to align + * @param page_size The page size to align to + * @return The aligned size + */ size_t PhysicalMemoryManager::align_up_to_page(size_t size, size_t page_size) { return (size + page_size - 1) & ~(page_size - 1); } - +/** + * @brief Checks if an address is aligned + * @param size The address to check + * @return True if the address is aligned + */ bool PhysicalMemoryManager::check_aligned(size_t size){ - return (size % PAGE_SIZE) == 0; + return (size % s_page_size) == 0; } +/** + * @brief Allocates a physical page of memory, if the PMM is not initalise it will use the anon memory instead of the bitmap + * @return The physical address of the page + */ void* PhysicalMemoryManager::allocate_frame() { // Check if the pmm is initialized @@ -140,16 +163,16 @@ void* PhysicalMemoryManager::allocate_frame() { // Find the first free frame while ((!is_anonymous_available(m_anonymous_memory_physical_address)) && (m_anonymous_memory_physical_address < m_memory_size)) { - m_anonymous_memory_physical_address += PAGE_SIZE; - m_anonymous_memory_virtual_address += PAGE_SIZE; + m_anonymous_memory_physical_address += s_page_size; + m_anonymous_memory_virtual_address += s_page_size; } // Mark frame as used - m_anonymous_memory_physical_address += PAGE_SIZE; - m_anonymous_memory_virtual_address += PAGE_SIZE; + m_anonymous_memory_physical_address += s_page_size; + m_anonymous_memory_virtual_address += s_page_size; // Return the address - return (void*)(m_anonymous_memory_physical_address - PAGE_SIZE); + return (void*)(m_anonymous_memory_physical_address - s_page_size); } @@ -170,7 +193,7 @@ void* PhysicalMemoryManager::allocate_frame() { // Return the address uint64_t frame_address = (row * ROW_BITS) + column; - return (void*)(frame_address * PAGE_SIZE); + return (void*)(frame_address * s_page_size); } } @@ -179,18 +202,26 @@ void* PhysicalMemoryManager::allocate_frame() { } - +/** + * @brief Frees a frame in the bit map + * @param address The address to free + */ void PhysicalMemoryManager::free_frame(void *address) { // Mark the frame as not used m_used_frames--; // Set the bit to 0 - uint64_t frame_address = (uint64_t)address / PAGE_SIZE; + uint64_t frame_address = (uint64_t)address / s_page_size; m_bit_map[frame_address / ROW_BITS] &= ~(1 << (frame_address % ROW_BITS)); } - +/** + * @brief Allocate an area of physical memory + * @param start_address The start of the block + * @param size The size to allocate + * @return A pointer to the start of the block (physical address) + */ void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) { // Check how many frames are needed @@ -229,7 +260,7 @@ void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) m_bit_map[start_row + (start_column + i) / ROW_BITS] |= (1 << ((start_column + i) % ROW_BITS)); // Return the address - return (void*)(start_address + (start_row * ROW_BITS + start_column) * PAGE_SIZE); + return (void*)(start_address + (start_row * ROW_BITS + start_column) * s_page_size); } } } @@ -238,11 +269,16 @@ void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) return nullptr; } +/** + * @brief Frees an area of physical memory + * @param start_address The start of the block + * @param size The size to free + */ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { // Check how many frames are needed size_t frame_count = size_to_frames(size); - uint64_t frame_address = start_address / PAGE_SIZE; + uint64_t frame_address = start_address / s_page_size; // Check if the address is valid if(frame_address >= m_bitmap_size) @@ -255,6 +291,12 @@ void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) { } +/** + * @brief Checks if a sub table is available a table, if not it is created + * @param table The table to check + * @param next_table The table to create + * @param index The index of the table to create + */ void PhysicalMemoryManager::create_table(pml_t* table, pml_t* next_table, size_t index) { // If the table is already created return @@ -272,6 +314,13 @@ void PhysicalMemoryManager::create_table(pml_t* table, pml_t* next_table, size_t } +/** + * @brief Gets or creates a table in a table + * @param table The table to check + * @param index The index of the table to get or create + * @param flags The flags to set the table to + * @return The created table + */ uint64_t* PhysicalMemoryManager::get_or_create_table(uint64_t *table, size_t index, size_t flags) { // Address mask @@ -295,6 +344,12 @@ uint64_t* PhysicalMemoryManager::get_or_create_table(uint64_t *table, size_t ind return new_table; } +/** + * @brief Checks if a table has an entry + * @param table The table to check + * @param index The index of the table to check + * @return True if the table has an entry + */ bool PhysicalMemoryManager::table_has_entry(pml_t *table, size_t index) { // Get the entry pte_t* entry = &table -> entries[index]; @@ -304,6 +359,12 @@ bool PhysicalMemoryManager::table_has_entry(pml_t *table, size_t index) { } +/** + * @brief Gets a table if it exists + * @param table The table to check + * @param index The index of the table to get + * @return The table if it exists, nullptr otherwise + */ uint64_t *PhysicalMemoryManager::get_table_if_exists(uint64_t *table, size_t index) { // Address mask @@ -320,6 +381,13 @@ uint64_t *PhysicalMemoryManager::get_table_if_exists(uint64_t *table, size_t ind } #define ENTRIES_TO_ADDRESS(pml4, pdpr, pd, pt)((pml4 << 39) | (pdpr << 30) | (pd << 21) | (pt << 12)) +/** + * @brief Maps a physical address to a virtual address, using the kernel's pml4 table + * @param physical_address The physical address to map + * @param address The virtual address to map to + * @param flags The flags to set the mapping to + * @return The virtual address + */ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_address, virtual_address_t* address, size_t flags) { // Base information @@ -359,6 +427,14 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical_addre return address; } +/** + * @brief Maps a physical address to a virtual address + * @param physical The physical address + * @param virtual_address The virtual address + * @param flags The flags to set the mapping to + * @param pml4_table The pml4 table to use + * @return The virtual address + */ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virtual_address_t *virtual_address, size_t flags, uint64_t *pml4_table) { // Get the indexes @@ -395,7 +471,12 @@ virtual_address_t* PhysicalMemoryManager::map(physical_address_t *physical, virt return virtual_address; } - +/** + * @brief Allocates a physical address to a virtual address + * @param virtual_address The virtual address + * @param flags The flags to set the mapping to + * @return The virtual address + */ virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address, size_t flags) { // Create a new physical address for the frame @@ -406,6 +487,12 @@ virtual_address_t* PhysicalMemoryManager::map(virtual_address_t *virtual_address } +/** + * @brief Allocates a new area physical memory to a area virtual address + * @param virtual_address_start The start of the virtual address + * @param length The length of the area + * @param flags The flags to set the mapping to + */ void PhysicalMemoryManager::map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags) { // Get the size of the area @@ -413,10 +500,17 @@ void PhysicalMemoryManager::map_area(virtual_address_t* virtual_address_start, s // Map the required frames for (size_t i = 0; i < size; ++i) - map(virtual_address_start + (i * PAGE_SIZE), flags); + map(virtual_address_start + (i * s_page_size), flags); } +/** + * @brief Maps an area of physical memory to a virtual address + * @param physical_address_start The start of the physical address + * @param virtual_address_start The start of the virtual address + * @param length The length of the area + * @param flags The flags to set the mapping to + */ void PhysicalMemoryManager::map_area(physical_address_t* physical_address_start, virtual_address_t* virtual_address_start, size_t length, size_t flags) { // Get the size of the area @@ -424,10 +518,15 @@ void PhysicalMemoryManager::map_area(physical_address_t* physical_address_start, // Map the required frames for (size_t i = 0; i < size; ++i) - map(physical_address_start + (i * PAGE_SIZE), virtual_address_start + (i * PAGE_SIZE), flags); + map(physical_address_start + (i * s_page_size), virtual_address_start + (i * s_page_size), flags); } +/** + * @brief Maps a physical address to its virtual address counter-part + * @param physical_address The physical address to map + * @param flags The flags to set the mapping to + */ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, size_t flags) { // Map the physical address to its virtual address counter-part @@ -435,6 +534,10 @@ void PhysicalMemoryManager::identity_map(physical_address_t *physical_address, s } +/** + * @brief Unmaps a virtual address using the kernel's pml4 table + * @param virtual_address The virtual address to unmap + */ void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { // Base information @@ -467,6 +570,11 @@ void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address) { asm volatile("invlpg (%0)" ::"r" (virtual_address) : "memory"); } +/** + * @brief Unmaps a virtual address + * @param virtual_address The virtual address to unmap + * @param pml4_root The pml4 table to use + */ void PhysicalMemoryManager::unmap(virtual_address_t *virtual_address, uint64_t *pml4_root) { // Get the indexes @@ -497,6 +605,11 @@ void PhysicalMemoryManager::unmap(virtual_address_t *virtual_address, uint64_t * } +/** + * @brief Unmaps an area of virtual memory + * @param virtual_address_start The start of the area + * @param length The length of the area + */ void PhysicalMemoryManager::unmap_area(virtual_address_t *virtual_address_start, size_t length) { // Get the size of the area @@ -504,7 +617,7 @@ void PhysicalMemoryManager::unmap_area(virtual_address_t *virtual_address_start, // Unmap the required frames for (size_t i = 0; i < size; ++i) - unmap(virtual_address_start + (i * PAGE_SIZE)); + unmap(virtual_address_start + (i * s_page_size)); } /** @@ -518,13 +631,22 @@ bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virt // TODO: Implement } - +/** + * @brief Cleans a page table (fills it with 0 or null entries) + * @param table The table to clean + */ void PhysicalMemoryManager::clean_page_table(uint64_t *table) { for(int i = 0; i < 512; i++){ table[i] = 0x00l; } } +/** + * @brief Creates a page table entry + * @param address The address to create the entry for + * @param flags The flags to set the entry to + * @return The created page table entry + */ pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) { pte_t page = (pte_t){ @@ -544,10 +666,15 @@ pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t f return page; } +/** + * @brief Checks if a physical address is reserved by multiboot mmap + * @param address The address to check + * @return True if the address is reserved + */ bool PhysicalMemoryManager::is_anonymous_available(size_t address) { // Return false if the address range is entirely within or overlaps with the multiboot reserved region - if ((address > multiboot_tag_start && address + PAGE_SIZE < multiboot_tag_end) || (address + PAGE_SIZE > multiboot_tag_start && address < multiboot_tag_end)) { + if ((address > multiboot_tag_start && address + s_page_size < multiboot_tag_end) || (address + s_page_size > multiboot_tag_start && address < multiboot_tag_end)) { return false; } @@ -555,7 +682,7 @@ bool PhysicalMemoryManager::is_anonymous_available(size_t address) { for (multiboot_mmap_entry *entry = m_mmap_tag->entries; (multiboot_uint8_t *)entry < (multiboot_uint8_t *)m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry *)((unsigned long)entry + m_mmap_tag->entry_size)) { // If it doesn't overlap with the mmap entry - if ((entry -> addr + entry -> len) < (address + PAGE_SIZE)) + if ((entry -> addr + entry -> len) < (address + s_page_size)) continue; // If it is not available @@ -575,6 +702,11 @@ bool PhysicalMemoryManager::is_anonymous_available(size_t address) { return false; } +/** + * @brief Checks if an address is reserved by a multiboot module + * @param address The address to check + * @return True if the address is reserved + */ bool PhysicalMemoryManager::is_multiboot_reserved(uint64_t address) { //ASSERT(false, "Not implemented!") // TODO: Check if address is reserve by multiboot module @@ -582,6 +714,10 @@ bool PhysicalMemoryManager::is_multiboot_reserved(uint64_t address) { return false; } +/** + * @brief Gets the address of the bitmap + * @return The address of the bitmap + */ uint64_t *PhysicalMemoryManager::get_bitmap_address() { @@ -616,10 +752,18 @@ uint64_t *PhysicalMemoryManager::get_bitmap_address() { ASSERT(false, "No space for the bitmap"); } +/** + * @brief Gets the pml4 root address for the kernel + * @return The pml4 root address + */ uint64_t *PhysicalMemoryManager::get_pml4_root_address() { return m_pml4_root_address; } +/** + * @brief Gets total the memory size available for use (allocated or not) + * @return The memory size + */ uint64_t PhysicalMemoryManager::get_memory_size() { return m_memory_size; } diff --git a/kernel/src/memory/virtual.cpp b/kernel/src/memory/virtual.cpp index 36083a81..b1ae0cfe 100644 --- a/kernel/src/memory/virtual.cpp +++ b/kernel/src/memory/virtual.cpp @@ -45,7 +45,7 @@ VirtualMemoryManager::VirtualMemoryManager(bool is_kernel) }; // Space to store VMM chunks - uint64_t vmm_space = PhysicalMemoryManager::align_to_page(MemoryManager::s_hh_direct_map_offset + m_physical_memory_manager->get_memory_size() + PhysicalMemoryManager::PAGE_SIZE); + uint64_t vmm_space = PhysicalMemoryManager::align_to_page(MemoryManager::s_hh_direct_map_offset + m_physical_memory_manager->get_memory_size() + PhysicalMemoryManager::s_page_size); m_first_region = (virtual_memory_region_t*)vmm_space; m_current_region = m_first_region; @@ -57,7 +57,7 @@ VirtualMemoryManager::VirtualMemoryManager(bool is_kernel) _kprintf("Allocated VMM: physical: 0x%x, virtual: 0x%x\n", vmm_space_physical, vmm_space); // Calculate the next available address - m_next_available_address = PhysicalMemoryManager::PAGE_SIZE; + m_next_available_address = PhysicalMemoryManager::s_page_size; if(m_is_kernel){ // Kernel needs to start at the higher half @@ -74,15 +74,25 @@ VirtualMemoryManager::~VirtualMemoryManager() { } - +/** + * @brief Allocate a new chunk of virtual memory + * @param size The size of the memory to allocate + * @param flags The flags to set on the memory + * @return The address of the allocated memory + */ void* VirtualMemoryManager::allocate(size_t size, size_t flags) { return allocate(0, size, flags); } - +/** + * @brief Allocate a new chunk of virtual memory at a specific address (ie for mmap io devices) + * @param address The address to allocate at + * @param size The size of the memory to allocate + * @param flags The flags to set on the memory + * @return The address of the allocated memory or nullptr if failed + */ void *VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags) { - /// This is used when we need to allocate at a specific address (ie reserving for mmap io devices) // Make sure allocating something if(size == 0) @@ -102,7 +112,7 @@ void *VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags } // Make sure the size is aligned - size = PhysicalMemoryManager::align_up_to_page(size, PhysicalMemoryManager::PAGE_SIZE); + size = PhysicalMemoryManager::align_up_to_page(size, PhysicalMemoryManager::s_page_size); // Is there space in the current region if(m_current_chunk >= s_chunks_per_page) @@ -136,7 +146,7 @@ void *VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags ASSERT(frame != nullptr, "Failed to allocate frame"); // Map the frame - m_physical_memory_manager->map(frame, (virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::PAGE_SIZE), Present | Write, m_pml4_root_address); + m_physical_memory_manager->map(frame, (virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::s_page_size), Present | Write, m_pml4_root_address); } @@ -144,7 +154,9 @@ void *VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags return (void*)chunk->start_address; } - +/** + * @brief Create a mew region in the VMM to use for allocation of more chunks + */ void VirtualMemoryManager::new_region() { // Space for the new region @@ -152,7 +164,7 @@ void VirtualMemoryManager::new_region() { ASSERT(new_region_physical != nullptr, "Failed to allocate new VMM region"); // Align the new region - virtual_memory_region_t* new_region = (virtual_memory_region_t*)PhysicalMemoryManager::align_to_page((uint64_t)m_current_region + PhysicalMemoryManager::PAGE_SIZE); + virtual_memory_region_t* new_region = (virtual_memory_region_t*)PhysicalMemoryManager::align_to_page((uint64_t)m_current_region + PhysicalMemoryManager::s_page_size); // Map the new region m_physical_memory_manager->map(new_region_physical, (virtual_address_t*)new_region, Present | Write, m_pml4_root_address); @@ -164,6 +176,11 @@ void VirtualMemoryManager::new_region() { m_current_region = new_region; } + +/** + * @brief Free a chunk of virtual memory + * @param address The address of the memory to free + */ void VirtualMemoryManager::free(void *address) { // Make sure freeing something @@ -202,7 +219,7 @@ void VirtualMemoryManager::free(void *address) { for (size_t i = 0; i < pages; i++){ // Unmap the frame - m_physical_memory_manager->unmap((virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::PAGE_SIZE), m_pml4_root_address); + m_physical_memory_manager->unmap((virtual_address_t*)chunk->start_address + (i * PhysicalMemoryManager::s_page_size), m_pml4_root_address); } @@ -213,6 +230,11 @@ void VirtualMemoryManager::free(void *address) { // TODO: Some logic to use this space again } + +/** + * @brief Returns the amount of memory used + * @return The amount of memory used + */ size_t VirtualMemoryManager::memory_used() { // Loop through all the regions and add up the size of the allocated chunks From cf5e160363bcace0dee4dc842c50ac5969aac1f8 Mon Sep 17 00:00:00 2001 From: Max Tyson <98maxt98@gmail.com> Date: Sun, 13 Oct 2024 22:03:27 +1300 Subject: [PATCH 29/29] Fix Issues --- kernel/include/memory/memorymanagement.h | 1 - kernel/src/kernel.cpp | 7 +------ kernel/src/memory/memorymanagement.cpp | 2 -- toolchain/make_cross_compiler.sh | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/kernel/include/memory/memorymanagement.h b/kernel/include/memory/memorymanagement.h index 6f192a4b..6e5b5ab9 100644 --- a/kernel/include/memory/memorymanagement.h +++ b/kernel/include/memory/memorymanagement.h @@ -44,7 +44,6 @@ namespace MaxOS{ public: static MemoryManager* s_active_memory_manager; - static const uint64_t s_higher_half_offset { 0xFFFFFFFF80000000 }; static const uint64_t s_higher_half_kernel_offset { 0xFFFFFFFF80000000 }; static const uint64_t s_higher_half_mem_offset { 0xFFFF800000000000 }; diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index 59f244c2..9b0e0b91 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -110,9 +110,6 @@ extern volatile uint64_t p4_table[512]; extern "C" void kernelMain(unsigned long addr, unsigned long magic) { - // Make the multiboot header - Multiboot multiboot(addr); - // Initialise the serial console SerialConsole serialConsole; @@ -132,10 +129,8 @@ extern "C" void kernelMain(unsigned long addr, unsigned long magic) _kprintf("-= Virtual Memory Manager set up =-\n"); + // Initialise the memory manager MemoryManager memoryManager(&vmm); - void* test = memoryManager.malloc(100); - memoryManager.free(test); - _kprintf("-= Memory Manager set up =-\n"); // Now entered the gui space diff --git a/kernel/src/memory/memorymanagement.cpp b/kernel/src/memory/memorymanagement.cpp index 046e971c..54f198dd 100644 --- a/kernel/src/memory/memorymanagement.cpp +++ b/kernel/src/memory/memorymanagement.cpp @@ -191,8 +191,6 @@ int MemoryManager::memory_used() { return result; } -uint64_t MemoryManager::map_to_higher_half(uint64_t physical_address) { - /** * @brief Aligns the size to the chunk alignment diff --git a/toolchain/make_cross_compiler.sh b/toolchain/make_cross_compiler.sh index 4197d03d..54b06ff6 100755 --- a/toolchain/make_cross_compiler.sh +++ b/toolchain/make_cross_compiler.sh @@ -5,7 +5,7 @@ source ./MaxOS.sh if [ "$1" != "--no-deps" ]; then msg "Installing extra dependencies" sudo apt update - sudo apt install -y build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libisl-dev cmake nasm + sudo apt install -y build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libisl-dev cmake nasm telnet fi # Make A Directory For The Cross Compiler