// |$|*file*kernel.c*| |$|*noclean*| // |$|*artifact*kernel.o*kernel.c*"gcc -ffreestanding -nostdlib -c {artifact0} -o {file}"*| // |$|*artifact*kernel.bin*kernel.ld&kernel.o*"ld -flto -T {artifact0} {artifact1} -S -o {file}"*| #include #include #define true 1 #define false 0 typedef void (*diskread_fn)(void *buffer, uint32_t lba); typedef struct SMAP_entry { uint32_t BaseL; // base address uint64_t uint32_t BaseH; uint32_t LengthL; // length uint64_t uint32_t LengthH; uint32_t Type; // entry Type uint32_t ACPI; // extended }__attribute__((packed)) SMAP_entry_t; typedef uint64_t page_table_entry_t; void KernelMain(SMAP_entry_t* e820_buffer, uint16_t e820_entry_count); diskread_fn diskRead; void _start(diskread_fn a1, void* e820_buffer, uint16_t e820_entry_count) { diskRead = a1; KernelMain(e820_buffer, e820_entry_count); } // --- Constants --- #define PAGE_PRESENT (1 << 0) #define PAGE_WRITE (1 << 1) #define PAGE_USER (1 << 2) #define PAGE_SIZE_2MB (1 << 7) #define ALIGN_4K __attribute__((aligned(4096))) #define PHYS_MEM_OFFSET 0xFFFF800000000000 #define BOOTSTRAP_MEM_END 0x200000 // 2MiB // --- Hardcoded Page Tables --- page_table_entry_t *pml4 = (page_table_entry_t*)0x1000; page_table_entry_t *pdp = (page_table_entry_t*)0x2000; page_table_entry_t *pd = (page_table_entry_t*)0x3000; page_table_entry_t *pt = (page_table_entry_t*)0x4000; page_table_entry_t *pt2 = (page_table_entry_t*)0x4000; // --- Free-List Allocator --- typedef struct free_block { size_t size; struct free_block* next; } free_block_t; volatile static uint64_t *debug = 0x7200; static free_block_t* free_list = NULL; void* alloc(size_t size) { free_block_t* prev = NULL; free_block_t* curr = free_list; while (curr) { if (curr->size >= size) { if (curr->size > size + sizeof(free_block_t)) { // Split block free_block_t* new_block = (free_block_t*)((uint8_t*)curr + size); new_block->size = curr->size - size; new_block->next = curr->next; curr->size = size; if (prev) prev->next = new_block; else free_list = new_block; } else { // Use whole block if (prev) prev->next = curr->next; else free_list = curr->next; } return (void*)curr; } prev = curr; curr = curr->next; } *debug = 0xEEEE0002; while(1){} return NULL; // No suitable block } void* alloc_aligned_4k(size_t size) { // Allocate extra space to ensure alignment size_t total_size = size + 4096; // Allocate using the free-list allocator void* ptr = alloc(total_size); if (!ptr) { *debug = 0xEEEE0001; while(1){} return NULL; // Allocation failed } // Calculate the aligned address uintptr_t aligned_addr = ((uintptr_t)ptr + 4095) & ~4095; // If the aligned address is the same as the original, return it if (aligned_addr == (uintptr_t)ptr) { return ptr; } // Otherwise, adjust the free list to account for the unused space size_t unused_space = aligned_addr - (uintptr_t)ptr; // If there's enough unused space to split into a new free block if (unused_space >= sizeof(free_block_t)) { free_block_t* new_free_block = (free_block_t*)ptr; new_free_block->size = unused_space; new_free_block->next = free_list; free_list = new_free_block; } // Return the aligned address return (void*)aligned_addr; } void free(void* ptr, size_t size) { free_block_t* block = (free_block_t*)ptr; block->size = size; block->next = free_list; free_list = block; } void merge_adjacent_blocks() { if (!free_list || !free_list->next) { // No merging possible if there are 0 or 1 blocks return; } free_block_t *curr = free_list; free_block_t *prev = NULL; while (curr && curr->next) { // Check if the current block is adjacent to the next block if ((uint8_t *)curr + curr->size == (uint8_t *)curr->next) { // Merge current and next block curr->size += curr->next->size; curr->next = curr->next->next; // Do not advance 'curr' yet, as the next block might also be adjacent } else { // Move to the next block prev = curr; curr = curr->next; } } } static inline void reload_cr3(uint64_t pml4_phys_addr) { asm volatile( "mov %0, %%cr3" : : "r"(pml4_phys_addr) : "memory" ); } // --- Paging --- void map_page(uint64_t phys_addr, uint64_t virt_addr) { uint64_t pml4_idx = (virt_addr >> 39) & 0x1FF; uint64_t pdp_idx = (virt_addr >> 30) & 0x1FF; uint64_t pd_idx = (virt_addr >> 21) & 0x1FF; uint64_t pt_idx = (virt_addr >> 12) & 0x1FF; // Allocate PDP if not present if (!(pml4[pml4_idx] & PAGE_PRESENT)) { page_table_entry_t* new_pdp = alloc_aligned_4k(4096); for (int i = 0; i < 512; i++) new_pdp[i] = 0; pml4[pml4_idx] = (uint64_t)new_pdp | PAGE_PRESENT | PAGE_WRITE; } page_table_entry_t* pdp_ptr = (page_table_entry_t*)(pml4[pml4_idx] & ~0xFFF); // Allocate PD if not present if (!(pdp_ptr[pdp_idx] & PAGE_PRESENT)) { page_table_entry_t* new_pd = alloc_aligned_4k(4096); for (int i = 0; i < 512; i++) new_pd[i] = 0; pdp_ptr[pdp_idx] = (uint64_t)new_pd | PAGE_PRESENT | PAGE_WRITE; } page_table_entry_t* pd_ptr = (page_table_entry_t*)(pdp_ptr[pdp_idx] & ~0xFFF); // Allocate PT if not present if (!(pd_ptr[pd_idx] & PAGE_PRESENT)) { page_table_entry_t* new_pt = alloc_aligned_4k(4096); for (int i = 0; i < 512; i++) new_pt[i] = 0; pd_ptr[pd_idx] = (uint64_t)new_pt | PAGE_PRESENT | PAGE_WRITE; } page_table_entry_t* pt_ptr = (page_table_entry_t*)(pd_ptr[pd_idx] & ~0xFFF); // Map the physical page pt_ptr[pt_idx] = phys_addr | PAGE_PRESENT | PAGE_WRITE; } // --- Kernel Main --- void KernelMain(SMAP_entry_t* e820_buffer, uint16_t e820_entry_count) { // 1. Initialize hardcoded page tables for (int i = 0; i < 512; i++) { pml4[i] = 0; pdp[i] = 0; pd[i] = 0; pt[i] = 0; pt2[i]= 0; } // 2. Identity map first 2MiB pml4[0] = (uint64_t)pdp | PAGE_PRESENT | PAGE_WRITE; pdp[0] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITE; pd[0] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITE; pd[1] = (uint64_t)pt2| PAGE_PRESENT | PAGE_WRITE; for (int i = 0; i < 512; i++) { pt[i] = (i * 4096) | PAGE_PRESENT | PAGE_WRITE; //pt2[i]= (PHYS_MEM_OFFSET + (i * 4096)) | PAGE_PRESENT | PAGE_WRITE; } // --- Map first 2MiB at PHYS_MEM_OFFSET --- // We'll use pt2 for the offset mapping // Set up the paging hierarchy for PHYS_MEM_OFFSET // PHYS_MEM_OFFSET = 0xFFFF800000000000 // Indices for PHYS_MEM_OFFSET uint64_t pml4_off_idx = (PHYS_MEM_OFFSET >> 39) & 0x1FF; uint64_t pdp_off_idx = (PHYS_MEM_OFFSET >> 30) & 0x1FF; uint64_t pd_off_idx = (PHYS_MEM_OFFSET >> 21) & 0x1FF; // Allocate new tables for offset mapping if needed // For this hardcoded setup, reuse pdp, pd, pt2 pml4[pml4_off_idx] = (uint64_t)pdp | PAGE_PRESENT | PAGE_WRITE; pdp[pdp_off_idx] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITE; pd[pd_off_idx] = (uint64_t)pt2 | PAGE_PRESENT | PAGE_WRITE; for (int i = 0; i < 512; i++) { pt2[i] = (i * 4096) | PAGE_PRESENT | PAGE_WRITE; } reload_cr3((uint64_t)pml4); for (int i = 1; i < e820_entry_count; i++) { if (e820_buffer[i].Type!=1) continue; uint64_t base = ((uint64_t)e820_buffer[i].BaseH << 32) | e820_buffer[i].BaseL; uint64_t length = ((uint64_t)e820_buffer[i].LengthH << 32) | e820_buffer[i].LengthL; if (base > 0x200000) continue; if (base+length > 0x200000) { ... } else { ... } } while(1){} // 3. Map all physical memory for (int i = 1; i < e820_entry_count; i++) { if (e820_buffer[i].Type != 1) continue; // Skip non-usable memory uint64_t base = ((uint64_t)e820_buffer[i].BaseH << 32) | e820_buffer[i].BaseL; uint64_t length = ((uint64_t)e820_buffer[i].LengthH << 32) | e820_buffer[i].LengthL; for (uint64_t addr = base; addr < base + length; addr += 4096) { uint64_t virt_addr = PHYS_MEM_OFFSET + addr; //map_page(addr, virt_addr); /*reload_cr3((uint64_t)pml4); free_block_t* block = (free_block_t*)virt_addr; block->size=4096; block->next = 0; free_block_t* last_block = free_list; while(last_block->next){ last_block=last_block->next; } last_block->next = block;*/ merge_adjacent_blocks(); } } *debug = 0xbeef1337; while(1){} // 4. Initialize free_list with mapped memory // (Add code here to populate free_list with mapped memory) }