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