diff --git a/Makefile b/Makefile index 78d922a..cc8a534 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CC=cc LD=ld CFLAGS=-std=c2x -ffreestanding -fno-stack-protector -g -Wall -Wextra -pedantic -lgcc -isystem $(INCLUDE_DIR) - +CFLAGS+= -DPAGE_SIZE=4096 C_SRC=$(shell find $(SRC_DIR) -type f -name "*.c") C_OBJ=$(patsubst %.c,$(BUILD_DIR)/%.o,$(C_SRC)) @@ -46,5 +46,5 @@ $(BUILD_DIR)/$(ISO_NAME): $(BUILD_DIR)/$(K_BIN_NAME) grub.cfg cp $(BUILD_DIR)/$(K_BIN_NAME) $(BUILD_DIR)/iso/boot grub-mkrescue -o $(BUILD_DIR)/$(ISO_NAME) $(BUILD_DIR)/iso -run: +run: all qemu-system-x86_64 $(BUILD_DIR)/$(ISO_NAME) -serial stdio diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..bec05f8 --- /dev/null +++ b/include/memory.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +struct memory_segment { + uint64_t addr; + uint64_t len; + uint32_t type; + uint32_t reserved; +} __attribute__((packed)); + +struct memory_map { + uint32_t size; + uint32_t version; + struct memory_segment entries[]; +} __attribute__((packed)); + +/** + * Initalize system memory allocator + */ +extern void memory_init(struct memory_map *map); + +/** + * Disabled cpu interupts to not interfere with + * current memory allocations. + */ +extern void memory_lock(void); + +/** + * Reenabled cpu interupts + */ +extern void memory_unlock(void); + +/** + * @returns how much memory the system has + */ +extern uint64_t memory_total(void); + +/** + * @returns how much memory is free + */ +extern uint64_t memory_free(void); + +/** + * @returns how much memory is used + */ +extern uint64_t memory_used(void); + +/** + * Allocates a single page in memory. + * @returns the page if allocated or NULL on failure + */ +extern void *alloc_page(void); + +/** + * Allocats count pages in memory + * @param count - the number of continious pages to allocate + * @returns the pages if allocated or NULL on failure + */ +extern void *alloc_pages(int count); + +/** + * Frees a single page in memory + * @param page - the pointer to the page + */ +extern void free_page(void *page); + +/** + * Allocates at least len bytes of memory starting at + * physical address addr. Returned address can be + * any virtural address. + * @param addr - the physical address to map + * @param len - the minimum length to map + * @param writable - if this memory should be writable + * @param user - if this memory should be user writable + */ +extern void *mmap(void *addr, size_t len); + +/** + * Unmaps mapped address from the mmap function + * @param addr - the address returned from mmap + * @param len - the length allocated + */ +extern void unmap(void *addr); + +/** + * Allocates size_t bytes in memory + * @param size - the amount of bytes to allocate + * @retruns the address allocated or NULL on failure + */ +extern void *malloc(size_t size); + +/** + * Reallocates a given allocated ptr to a new size of bytes in memory. + * If ptr is NULL it will allocate new memory. + * @param ptr - the pointer to reallocate + * @param size - the amount of bytes to set the pointer to + * @returns the address allocated or NULL on failure + */ +extern void *realloc(void *ptr, size_t size); + +/** + * Frees a allocated pointer in memory + * @param ptr - the pointer to free + */ +extern void free(void *ptr); diff --git a/include/memory/physalloc.h b/include/memory/physalloc.h new file mode 100644 index 0000000..f22432e --- /dev/null +++ b/include/memory/physalloc.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef MEMORY_INTERNAL + #error "Do not include headers from , only use " +#endif + +/** + * Allocates a single physical page in memory + * @preturns the physical address of the page + */ +extern void *alloc_phys_page(void); + +/** + * Allocates count physical pages in memory + * @returns the physical address of the first page + */ +extern void *alloc_phys_pages(int count); + +/** +* Frees a single physical page in memory + * @param ptr - the physical address of the page + */ +extern void free_phys_page(void *ptr); + +/** + * Frees count physical pages in memory + * @param ptr - the physical address of the first page + * @param count - the number of pages in the list + */ +extern void free_phys_pages(void *ptr, int count); diff --git a/include/memory/virtalloc.h b/include/memory/virtalloc.h new file mode 100644 index 0000000..c4bac56 --- /dev/null +++ b/include/memory/virtalloc.h @@ -0,0 +1,24 @@ +#pragma once + +#ifndef MEMORY_INTERNAL + #error "Do not include headers from , only use " +#endif + +/** + * Initalizes the virtual address allocator + */ +void virtaddr_init(void); + +/** + * Allocate a virtual address of length x pages + * @param pages - x pages + * @returns virt addr + */ +void *virtaddr_alloc(int pages); + +/** + * Free the virtual address from virtaddr_alloc + * @param virtaddr - the addr to free + * @returns number of pages used for virtaddr + */ +long virtaddr_free(void *virtaddr); diff --git a/include/shim.h b/include/shim.h new file mode 100644 index 0000000..a0f0156 --- /dev/null +++ b/include/shim.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +struct boot_info { + struct memory_map *map; +}; diff --git a/include/term.h b/include/term.h new file mode 100644 index 0000000..07ebacb --- /dev/null +++ b/include/term.h @@ -0,0 +1,3 @@ +#pragma once + + diff --git a/src/arch/amd64/boot.S b/src/arch/amd64/boot.S index 36e4bc6..447ac2f 100644 --- a/src/arch/amd64/boot.S +++ b/src/arch/amd64/boot.S @@ -1,4 +1,9 @@ global start +global pml4_list +global init_pdpt +global init_pd +global init_pt +global paging_pt extern kmain extern amd64_shim bits 32 @@ -19,6 +24,18 @@ dd 8 mb_end: section .bss +align 4096 +pml4_list: ; reserve memory for initial 512 pml4 entires + resb 4096 +init_pdpt: ; reserve memory for initial 512 pdpt entires + resb 4096 +init_pd: ; reserve memory for initial 512 pd entries + resb 4096 +init_pt: ; reserve memory for initial 512 pt entries + resb 4096 +paging_pt: ; reserve memory for 512 paging reserved pt entires + resb 4096 + align 16 stack_start: resb 16384 @@ -76,7 +93,7 @@ start: mov ecx, 4096 rep stosd mov edi, cr3 - + ; FIXME: Update boot.S to point base of paging to pml4e_list, see above mov DWORD [edi], 0x2003 ; Set the uint32_t at the destination index to 0x2003. add edi, 0x1000 ; Add 0x1000 to the destination index. mov DWORD [edi], 0x3003 ; Set the uint32_t at the destination index to 0x3003. diff --git a/src/arch/amd64/fb.c b/src/arch/amd64/fb.c index f27b890..07847e5 100644 --- a/src/arch/amd64/fb.c +++ b/src/arch/amd64/fb.c @@ -3,8 +3,12 @@ #include #include -#define PREFERRED_VY 4096 -#define PREFERRED_B 32 +#define INDEX 0x1CE +#define DATA 0x1CF +#define FB_ADDR 0xE0000000 + +#define PREFERRED_VY 4096 +#define PREFERRED_B 32 uint16_t fb_res_x = 0; uint16_t fb_res_y = 0; @@ -14,36 +18,36 @@ uint8_t *fb_buffer = NULL; int fb_init(uint16_t res_x, uint16_t res_y) { - outw(0x1CE, 0x00); - uint16_t i = inw(0x1CF); + outw(INDEX, 0x00); + uint16_t i = inw(DATA); if (i < 0xB0C0 || i > 0xB0C6) { return -1; } - outw(0x1CF, 0xB0C4); - i = inw(0x1CF); + outw(DATA, 0xB0C4); + i = inw(DATA); /* Disable VBE */ - outw(0x1CE, 0x04); - outw(0x1CF, 0x00); + outw(INDEX, 0x04); + outw(DATA, 0x00); /* Set X resolution to 1024 */ - outw(0x1CE, 0x01); - outw(0x1CF, res_x); + outw(INDEX, 0x01); + outw(DATA, res_x); /* Set Y resolution to 768 */ - outw(0x1CE, 0x02); - outw(0x1CF, res_y); + outw(INDEX, 0x02); + outw(DATA, res_y); /* Set bpp to 32 */ - outw(0x1CE, 0x03); - outw(0x1CF, PREFERRED_B); + outw(INDEX, 0x03); + outw(DATA, PREFERRED_B); /* Set Virtual Height to stuff */ - outw(0x1CE, 0x07); - outw(0x1CF, PREFERRED_VY); + outw(INDEX, 0x07); + outw(DATA, PREFERRED_VY); /* Re-enable VBE */ - outw(0x1CE, 0x04); - outw(0x1CF, 0x41); + outw(INDEX, 0x04); + outw(DATA, 0x41); uint32_t * text_vid_mem = (uint32_t *)0xA0000; text_vid_mem[0] = 0xA5ADFACE; - for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { + for (uintptr_t fb_offset = FB_ADDR; fb_offset < 0xFF000000; fb_offset += 0x01000000) { /* Enable the higher memory */ for (uintptr_t i = fb_offset; i < fb_offset; i += 0x1000) { // todo ident map fb diff --git a/src/arch/amd64/fb.h b/src/arch/amd64/fb.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/arch/amd64/linker.ld b/src/arch/amd64/linker.ld index 4e796e2..3dd90ff 100644 --- a/src/arch/amd64/linker.ld +++ b/src/arch/amd64/linker.ld @@ -2,6 +2,8 @@ ENTRY(start) SECTIONS { . = 1M; + + kernel_start = .; .boot BLOCK(4K) : ALIGN(4K) { @@ -22,4 +24,6 @@ SECTIONS { { *(.bss) } + + kernel_end = .; } diff --git a/src/arch/amd64/mboot.h b/src/arch/amd64/mboot.h index 88348f5..2d8c53c 100644 --- a/src/arch/amd64/mboot.h +++ b/src/arch/amd64/mboot.h @@ -1,5 +1,6 @@ #pragma once +#include "memory.h" #include #define CMDLINE_MAX 32 @@ -10,12 +11,14 @@ struct mboot_tag { uint32_t size; union { char cmdline[CMDLINE_MAX + 1]; + struct memory_map *memory_map; void *rootsdp; } data; }; enum mboot_tag_type { MBOOT_CMDLINE = 0, + MBOOT_MEMORYMAP = 6, MBOOT_XSDP = 14 }; diff --git a/src/arch/amd64/paging.c b/src/arch/amd64/paging.c new file mode 100644 index 0000000..3140a2a --- /dev/null +++ b/src/arch/amd64/paging.c @@ -0,0 +1,320 @@ +#include +#include +#include +#include + +#define MEMORY_INTERNAL +#include +#include + +#include "bindings.h" + +#define F_PRESENT 0x001 +#define F_WRITEABLE 0x002 +#define F_UNPRIVILEGED 0x004 +#define F_WRITETHROUGH 0x008 +#define F_CACHEDISABLE 0x010 +#define F_ACCESSED 0x020 +#define F_DIRTY 0x040 +#define F_MEGABYTE 0x080 +#define F_GLOBAL 0x100 + +// PAGE MAP LEVEL 4 ENTRY +struct pml4e { + uint64_t flags : 6; + uint64_t : 6; + uint64_t address : 40; + uint64_t : 11; + uint64_t execute_disable : 1; +}; + +// PAGE DIRECTORY POINTER TABLE ENTRY +struct pdpte { + uint64_t flags : 6; + uint64_t : 1; + uint64_t page_size : 1; + uint64_t : 4; + uint64_t address : 40; + uint64_t : 11; + uint64_t execute_disable : 1; +}; + +// PAGE DIRECTORY ENTRY +struct pde { + uint64_t flags : 6; + uint64_t : 1; + uint64_t page_size : 1; + uint64_t : 4; + uint64_t address : 40; + uint64_t : 11; + uint64_t execute_disable : 1; +}; + +// PAGE TABLE ENTRY +struct pte { + uint64_t flags : 9; + uint64_t : 3; + uint64_t address : 40; + uint64_t : 7; + uint64_t protection_key : 4; + uint64_t execute_disable : 1; +}; + +// bss segment, can write to +extern struct pml4e pml4_list[512]; +extern struct pdpte init_pdpt[512]; +extern struct pde init_pd[512]; +extern struct pte init_pt[512]; +extern struct pte paging_pt[512]; // paging_pt should NEVER be outside of this file, NEVER i say + +// paged address to read page tables +// the structures are not gurenteed to be ident mapped +// map them here with map_(phys_addr) before useing structures +static struct pdpte *pdpt_mapped = (void *) (uintptr_t) 0x1000; +static struct pdpte *pd_mapped = (void *) (uintptr_t) 0x2000; +static struct pdpte *pt_mapped = (void *) (uintptr_t) 0x3000; +void *addr_mapped = (void *) (uintptr_t) 0x4000; + +static inline void invlpg(void *addr) { + __asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); +} + +static void map_pdpt(struct pdpte *phys_addr) { + paging_pt[1].address = (((uint64_t)phys_addr) >> 12); + paging_pt[1].flags = F_PRESENT | F_WRITEABLE; + invlpg(pdpt_mapped); +} + +static void map_pd(struct pde *phys_addr) { + paging_pt[2].address = (((uint64_t)phys_addr) >> 12); + paging_pt[2].flags = F_PRESENT | F_WRITEABLE; + invlpg(pd_mapped); +} + +static void map_pt(struct pte *phys_addr) { + paging_pt[3].address = (((uint64_t)phys_addr) >> 12); + paging_pt[3].flags = F_PRESENT | F_WRITEABLE; + invlpg(pt_mapped); +} + +static void map_addr(void *phys_addr) { + paging_pt[4].address = (((uint64_t)phys_addr) >> 12); + paging_pt[4].flags = F_PRESENT | F_WRITEABLE; + invlpg(addr_mapped); +} + +//static int get_maxphysaddr() { +// uint32_t eax, ebx, ecx, edx; +// __cpuid(0x80000008, eax, ebx, ecx, edx); +// return eax & 0xFF; +//} + +//int find_phys_addr(struct pml4e *pml4, void *virt_addr, void **phys_addr) { +// uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; +// uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; +// uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; +// uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; +// uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; +// +// if (!(pml4[pml4_offset].flags & F_PRESENT)) +// return -1; +// struct pdpte *pdpt = (struct pdpte *)(pml4[pml4_offset].address << 12); +// if (!(pdpt[pdpt_offset].flags & F_PRESENT)) +// return -1; +// struct pde *pd = (struct pde *)(pdpt[pdpt_offset].address << 12); +// if (!(pd[pd_offset].flags & F_PRESENT)) +// return -1; +// struct pte *pt = (struct pte *)(pd[pd_offset].address << 12); +// if (!(pt[pt_offset].flags & F_PRESENT)) +// return -1; +// *phys_addr = (void *)((pt[pt_offset].address << 12) + page_offset); +// return 0; +//} + +char *curr_alloc = (void *) 0x5000; + +int map_page(struct pml4e *pml4, void *virt_addr, void *phys_addr, unsigned int flags) { + uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; + uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; + uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; + uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; + //uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; + + if (!(pml4[pml4_offset].flags & F_PRESENT)) { + void *new_page = alloc_phys_page(); + map_addr(new_page); + memset(addr_mapped, 0, 4096); + pml4[pml4_offset].address = ((uint64_t)new_page) >> 12; + } + pml4[pml4_offset].flags = F_PRESENT | flags; + + struct pdpte *__pdpt = (struct pdpte *)(uintptr_t)(pml4[pml4_offset].address << 12); + map_pdpt(__pdpt); + if (!(pdpt_mapped[pdpt_offset].flags & F_PRESENT)) { + void *new_page = alloc_phys_page(); + map_addr(new_page); + memset(addr_mapped, 0, 4096); + pdpt_mapped[pdpt_offset].address = ((uint64_t)new_page) >> 12; + } + pdpt_mapped[pdpt_offset].flags = F_PRESENT | flags; + + struct pde *__pd = (struct pde *)(uintptr_t)(pdpt_mapped[pdpt_offset].address << 12); + map_pd(__pd); + if (!(pd_mapped[pd_offset].flags & F_PRESENT)) { + void *new_page = alloc_phys_page(); + map_addr(new_page); + memset(addr_mapped, 0, 4096); + pd_mapped[pd_offset].address = ((uint64_t)new_page) >> 12; + } + pd_mapped[pd_offset].flags = F_PRESENT | flags; + + struct pte *__pt = (struct pte *)(uintptr_t)(pd_mapped[pd_offset].address << 12); + map_pt(__pt); + pt_mapped[pt_offset].flags = F_PRESENT | flags; + pt_mapped[pt_offset].address = (((uint64_t)phys_addr) >> 12); + invlpg(virt_addr); + return 0; +} + +int unmap_page(struct pml4e *pml4, void *virt_addr) { + uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; + uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; + uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; + uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; + //uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; + + if (!(pml4[pml4_offset].flags & F_PRESENT)) + return -1; + struct pdpte *__pdpt = (struct pdpte *)(uintptr_t)(pml4[pml4_offset].address << 12); + map_pdpt(__pdpt); + if (!(pdpt_mapped[pdpt_offset].flags & F_PRESENT)) + return -1; + struct pde *__pd = (struct pde *)(uintptr_t)(pdpt_mapped[pdpt_offset].address << 12); + map_pd(__pd); + if (!(pd_mapped[pd_offset].flags & F_PRESENT)) + return -1; + struct pte *__pt = (struct pte *)(uintptr_t)(pd_mapped[pd_offset].address << 12); + map_pt(__pt); + if (!(pt_mapped[pt_offset].flags & F_PRESENT)) + return -1; + + pt_mapped[pt_offset].flags = 0; + + int i = 0; + for(; i < 512; i++) { + if (pt_mapped[i].flags & F_PRESENT) + break; + } + if (i == 512) + goto done; + + pd_mapped[pd_offset].flags = 0; + + for(i = 0; i < 512; i++) { + if (pd_mapped[i].flags & F_PRESENT) + break; + } + if (i == 512) + goto done; + + pdpt_mapped[pdpt_offset].flags = 0; + + for(i = 0; i < 512; i++) { + if(pdpt_mapped[i].flags & F_PRESENT) + break; + } + if (i == 512) + goto done; + + pml4[pml4_offset].flags = 0; + + //TODO: Return memory used for page structures + +done: + invlpg(virt_addr); + return 0; +} + +void paging_init(void) { + memset(pml4_list, 0, 4096); + pml4_list[0].flags = F_PRESENT | F_WRITEABLE; + pml4_list[0].address = (uint64_t)init_pdpt >> 12; + + memset(init_pdpt, 0, 4096); + init_pdpt[0].flags = F_PRESENT | F_WRITEABLE; + init_pdpt[0].address = (uint64_t)init_pd >> 12; + + memset(pml4_list, 0, 4096); + init_pd[0].flags = F_PRESENT | F_WRITEABLE; + init_pd[0].address = (uint64_t)paging_pt >> 12; + init_pd[1].flags = F_PRESENT | F_WRITEABLE; + init_pd[1].address = (uint64_t)init_pt >> 12; + + memset(init_pt, 0, 4096); + memset(paging_pt, 0, 4096); +} + +static inline void *page_align(void *addr) { + uintptr_t a = (uintptr_t) addr; + a += PAGE_SIZE + 1; + a /= PAGE_SIZE; + return (void *) a; +} + +void *mmap(void *addr, size_t len) { + len += (uintptr_t)addr % PAGE_SIZE; + int pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + void *virt = virtaddr_alloc(pages); + if (virt == NULL) + return NULL; + void *phys = page_align(addr); + for (long i = 0; i < pages; i++) { + void *virt_temp = (char *)virt + (i * PAGE_SIZE); + void *phys_temp = (char *)phys + (i * PAGE_SIZE); + map_page(pml4_list, virt_temp, phys_temp, F_WRITEABLE); + } + return addr; +} + +void unmap(void *addr) { + long pages = virtaddr_free(addr); + for (long i = 0; i < pages; i++) { + void *virt = (char *)addr + (i * PAGE_SIZE); + unmap_page(pml4_list, virt); + } +} + +void *alloc_pages(int count) { + void *virt = virtaddr_alloc(count); + if (virt == NULL) + return NULL; + void *phys = alloc_phys_pages(count); + if (phys == NULL) { + virtaddr_free(virt); + return NULL; + } + for (int i = 0; i < count; i++) { + void *virt_temp = (char *)virt + (i * PAGE_SIZE); + void *phys_temp = (char *)phys + (i * PAGE_SIZE); + map_page(pml4_list, virt_temp, phys_temp, F_WRITEABLE); + } + return virt; +} + +void free_page(void *virt) { + long pages = virtaddr_free(virt); + if (pages < 1) + return; + for (long i = 0; i < pages; i++) { + void *virt_temp = (char *)virt + (i * PAGE_SIZE); + unmap_page(pml4_list, virt_temp); + } +} + +void memory_lock(void) { + cli(); +} + +void memory_unlock(void) { + sti(); +} diff --git a/src/arch/amd64/shim.c b/src/arch/amd64/shim.c index d17116a..dcd37bf 100644 --- a/src/arch/amd64/shim.c +++ b/src/arch/amd64/shim.c @@ -1,203 +1,36 @@ -#include #include #include #include +#include +#include -#define F_PRESENT 0x001 -#define F_WRITEABLE 0x002 -#define F_UNPRIVILEGED 0x004 -#define F_WRITETHROUGH 0x008 -#define F_CACHEDISABLE 0x010 -#define F_ACCESSED 0x020 -#define F_DIRTY 0x040 -#define F_MEGABYTE 0x080 -#define F_GLOBAL 0x100 - -// PAGE MAP LEVEL 4 ENTRY -struct pml4e { - uint64_t flags : 6; - uint64_t : 6; - uint64_t address : 40; - uint64_t : 11; - uint64_t execute_disable : 1; -}; - -// PAGE DIRECTORY POINTER TABLE ENTRY -struct pdpte { - uint64_t flags : 6; - uint64_t : 1; - uint64_t page_size : 1; - uint64_t : 4; - uint64_t address : 40; - uint64_t : 11; - uint64_t execute_disable : 1; -}; - -// PAGE DIRECTORY ENTRY -struct pde { - uint64_t flags : 6; - uint64_t : 1; - uint64_t page_size : 1; - uint64_t : 4; - uint64_t address : 40; - uint64_t : 11; - uint64_t execute_disable : 1; -}; - -// PAGE TABLE ENTRY -struct pte { - uint64_t flags : 9; - uint64_t : 3; - uint64_t address : 40; - uint64_t : 7; - uint64_t protection_key : 4; - uint64_t execute_disable : 1; -}; - -static inline void invlpg(unsigned long addr) { - __asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); -} - -static int get_maxphysaddr() { - uint32_t eax, ebx, ecx, edx; - __cpuid(0x80000008, eax, ebx, ecx, edx); - return eax & 0xFF; -} - -int find_phys_addr(struct pml4e *pml4, void *virt_addr, void **phys_addr) { - uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; - uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; - uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; - uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; - uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; - - if (!pml4[pml4_offset].flags & F_PRESENT) - return -1; - struct pdpte *pdpt = (struct pdpte *)(pml4[pml4_offset].address << 12); - if (!pdpt[pdpt_offset].flags & F_PRESENT) - return -1; - struct pde *pd = (struct pde *)(pdpt[pdpt_offset].address << 12); - if (!pd[pd_offset].flags & F_PRESENT) - return -1; - struct pte *pt = (struct pte *)(pd[pd_offset].address << 12); - if (!pt[pt_offset].flags & F_PRESENT) - return -1; - *phys_addr = (void *)((pt[pt_offset].address << 12) + page_offset); - return 0; -} - -char *curr_alloc = 0x5000; - -void *alloc_phys_page() { - void *ret = curr_alloc; - curr_alloc += 4096; - return ret; -} - -int map_page(struct pml4e *pml4, void *virt_addr, void *phys_addr, unsigned int flags) { - uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; - uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; - uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; - uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; - uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; - - if (!pml4[pml4_offset].flags & F_PRESENT) { - void *new_page = alloc_phys_page(); - memset(new_page, 0, 4096); - pml4[pml4_offset].address = ((uint64_t)new_page) >> 12; - pml4[pml4_offset].flags = F_PRESENT | flags; - } - struct pdpte *pdpt = (struct pdpte *)(pml4[pml4_offset].address << 12); - if (!pdpt[pdpt_offset].flags & F_PRESENT) { - void *new_page = alloc_phys_page(); - memset(new_page, 0, 4096); - pdpt[pdpt_offset].address = ((uint64_t)new_page) >> 12; - pdpt[pdpt_offset].flags = F_PRESENT | flags; - } - struct pde *pd = (struct pde *)(pdpt[pdpt_offset].address << 12); - if (!pd[pd_offset].flags & F_PRESENT) { - void *new_page = alloc_phys_page(); - memset(new_page, 0, 4096); - pd[pd_offset].address = ((uint64_t)new_page) >> 12; - pd[pd_offset].flags = F_PRESENT | flags; - } - struct pte *pt = (struct pte *)(pd[pd_offset].address << 12); - if (!pt[pt_offset].flags & F_PRESENT) { - pt[pt_offset].flags |= F_PRESENT | flags; - } - pt[pt_offset].address = (((uint64_t)phys_addr) >> 12); - invlpg(virt_addr); - return 0; -} - -int unmap_page(struct pml4e *pml4, void *virt_addr) { - uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39; - uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF; - uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF; - uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF; - uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF; - - if (!pml4[pml4_offset].flags & F_PRESENT) - return -1; - struct pdpte *pdpt = (struct pdpte *)(pml4[pml4_offset].address << 12); - if (!pdpt[pdpt_offset].flags & F_PRESENT) - return -1; - struct pde *pd = (struct pde *)(pdpt[pdpt_offset].address << 12); - if (!pd[pd_offset].flags & F_PRESENT) - return -1; - struct pte *pt = (struct pte *)(pd[pd_offset].address << 12); - if (!pt[pt_offset].flags & F_PRESENT) - return -1; - - pt[pt_offset].flags = 0; - - int i = 0; - for(; i < 512; i++) { - if (pt[i].flags & F_PRESENT) - break; - } - if (i == 512) - goto done; - - pd[pd_offset].flags = 0; - - for(i = 0; i < 512; i++) { - if (pd[i].flags & F_PRESENT) - break; - } - if (i == 512) - goto done; - - pdpt[pdpt_offset].flags = 0; - - for(i = 0; i < 512; i++) { - if(pdpt[i].flags & F_PRESENT) - break; - } - if (i == 512) - goto done; - - pml4[pml4_offset].flags = 0; - - //TODO: Return memory used for page structures - -done: - invlpg(virt_addr); - return 0; -} +#include "mboot.h" +static struct boot_info boot_info; // entry point for amd64 -void* amd64_shim(void *boot_info) { - struct pml4e *pml4 = (struct pml4e *)0x1000; - struct pdpte *pdpt = (struct pdpte *)0x2000; - struct pde *pd = (struct pde *)0x3000; - struct pte *pt = (struct pte *)0x4000; +void* amd64_shim(void *mboot_data_ptr) { + //struct pml4e *pml4 = (struct pml4e *)0x1000; + //struct pdpte *pdpt = (struct pdpte *)0x2000; + //struct pde *pd = (struct pde *)0x3000; + //struct pte *pt = (struct pte *)0x4000; //pd[1].flags = F_PRESENT | F_WRITEABLE; //pd[1].address = ((uint64_t)pt) >> 12; - map_page(pml4, 0x80000000, 0xB8002, F_WRITEABLE); + //map_page(pml4, (void *)0x80000000, (void *)0xB8002, F_WRITEABLE); //__asm("invlpg 0x200000"); - void *ret; - find_phys_addr(pml4, 0x80000000, &ret); - return ret; + //void *ret; + //find_phys_addr(pml4, (void *)0x80000000, &ret); + //return ret; + + struct mboot_info mboot_info; + mboot_info = mboot_load_info(mboot_data_ptr); + + struct mboot_tag *map_tag; + map_tag = mboot_get_tag(&mboot_info, MBOOT_MEMORYMAP); + + boot_info.map = map_tag->data.memory_map; + + return &boot_info; } + + diff --git a/src/kmain.c b/src/kmain.c index f7f2ec1..81f8c84 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -7,6 +7,6 @@ void kmain(void *info) { *(char*)0xB8000 = 'c'; //*(char*)(0xB8002 + 0x20'0000) = 'd'; itoa((long)info, buf, 16); - fb_init(1024, 768); + //fb_init(1024, 768); serial_out_str(buf); } diff --git a/src/memory/physalloc.c b/src/memory/physalloc.c new file mode 100644 index 0000000..b8eada6 --- /dev/null +++ b/src/memory/physalloc.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include + +#define MEMORY_INTERNAL +#include +#include + +extern uintptr_t kernel_start; +extern uintptr_t kernel_end; + +// between memory_start and kernel_start will be the bitmap +static uintptr_t memory_start = 0; + +typedef unsigned char page[4096]; + +struct memory_area { + uint64_t len; + uintptr_t addr; +}; + +static uint64_t *bitmap; +static uint64_t total_memory; +static uint64_t free_memory; +static uint64_t page_count; +static uint64_t page_free_start; +static struct memory_area *page_start; + +static int n_pages(const struct memory_area *m) { + return m->len / PAGE_SIZE; +} + +static void *page_at(int i) { + int cur_page = 0; + for (struct memory_area *m = page_start; m != NULL; m++) { + int pages = n_pages(m); + if (i - cur_page < pages) { + return (void *) (m->addr + (PAGE_SIZE * (i - cur_page))); + } + cur_page += pages; + } + return NULL; +} + +static long page_idx(page p) { + uintptr_t addr = (uintptr_t) p; + int cur_page = 0; + for (struct memory_area *m = page_start; m != NULL; m++) { + if ((uintptr_t) m + m->len > addr) { + return cur_page + ((addr - m->addr) / PAGE_SIZE); + } + cur_page += n_pages(m); + } + return -1; +} + +static inline bool bitmap_get(int i) { + return (bitmap[i / 64] >> i % 64) & 1; +} + +static inline void bitmap_set(int i, bool v) { + int idx = i / 64; + bitmap[idx] &= ~(1 << i % 64); + bitmap[idx] |= (v << i % 64); +} + +void *alloc_phys_page(void) { + return alloc_phys_pages(1); +} + +void *alloc_phys_pages(int pages) { + if (pages < 1) return NULL; + + int n_contiguous = 0; + int free_region_start = 0; + bool first = true; + for (uint64_t i = page_free_start; i < page_count; i++) { + bool free = !bitmap_get(i); + + if (first) { + first = false; + page_free_start = i; + } + + if (free) { + if (n_contiguous == 0) free_region_start = i; + n_contiguous++; + if (n_contiguous == pages) { + for (int j = 0; j < pages; j++) + bitmap_set(free_region_start + j, true); + return page_at(free_region_start); + } + } else n_contiguous = 0; + } + + return NULL; +} + +void free_phys_page(void *ptr) { + free_phys_pages(ptr, 1); +} + +void free_phys_pages(void *ptr, int pages) { + long idx = page_idx(ptr); + if (idx == -1) return; + + if ((unsigned) idx < page_free_start) page_free_start = idx; + + for (int i = 0; i < pages; i++) + bitmap_set(idx + pages, false); +} + +static bool segment_invalid(const struct memory_segment *segment) { + if (segment->type != 1) return false; + if (segment->addr < kernel_start) return false; + if (segment->addr + segment->len < memory_start) return false; + if (segment->addr + segment->len < kernel_start) return false; + return true; +} + +static struct memory_area segment_to_area(const struct memory_segment *segment) { + uint64_t length = segment->len; + uintptr_t addr = segment->addr; + + uintptr_t start; + if (memory_start) + start = memory_start; + else + start = kernel_end; + + if (segment->addr < start) { + addr = start; + length -= addr - segment->addr; + } else { + addr = segment->addr; + } + + struct memory_area temp; + temp.len = length; + temp.addr = addr; + + return temp; +} + +static uintptr_t page_align(uintptr_t ptr) { + return ptr + PAGE_SIZE - 1 / PAGE_SIZE; +} + +void memory_init(struct memory_map *map) { + + memory_lock(); + + virtaddr_init(); + + bitmap = NULL; + total_memory = 0; + free_memory = 0; + page_count = 0; + page_free_start = 0; + page_start = NULL; + + uintptr_t end = (uintptr_t) map; + end += map->size; + + struct memory_segment *segment = &map->entries[0]; + int segment_count = 0; + + for(; (uintptr_t) segment < end; segment++) { + if (segment_invalid(segment)) + continue; + + struct memory_area temp = segment_to_area(segment); + page_count += n_pages(&temp); + segment_count++; + } + + long bitmap_pages = page_count / 64 / PAGE_SIZE + 1; + free_memory = page_count * PAGE_SIZE; + + //HACK: terrible hack bad bad bad bad + long bitmap_size = bitmap_pages * PAGE_SIZE; + bitmap = (uint64_t *) page_at(page_count - bitmap_pages); + + long page_area_size = segment_count * sizeof(struct memory_area); + char *page_area_addr = (char *)bitmap + bitmap_size; + + bitmap = mmap(bitmap, bitmap_size); + memset(bitmap, 0, bitmap_size); + + memory_start = page_align(kernel_end + bitmap_size + page_area_size); + + page_area_addr = mmap(page_area_addr, page_area_size); + page_start = (struct memory_area *) page_area_addr; + + struct memory_area *area = page_start; + segment = &map->entries[0]; + + for(; (uintptr_t) segment < end; segment++) { + if (segment_invalid(segment)) + continue; + + struct memory_area temp = segment_to_area(segment); + *area = temp; + area++; + } + + page_count -= bitmap_pages; + + memory_unlock(); + +} + +void *alloc_page(void) { + return alloc_pages(1); +} + +uint64_t memory_total(void) { + return total_memory; +} + +uint64_t memory_free(void) { + return free_memory; +} + +uint64_t memory_used(void) { + return total_memory - free_memory; +} + +// stubs +// simon do these ik you want to +// :3 + +void *malloc(size_t size) { + //TODO: implement + (void)size; + return NULL; +} + +void *realloc(void *ptr, size_t size) { + //TODO: implement + (void)ptr; + (void)size; + return NULL; +} + +void free(void *ptr) { + //TODO: implement + (void)ptr; +} diff --git a/src/memory/virtalloc.c b/src/memory/virtalloc.c new file mode 100644 index 0000000..b8135ef --- /dev/null +++ b/src/memory/virtalloc.c @@ -0,0 +1,126 @@ +#include +#include +#include + +#define MEMORY_INTERNAL +#include + +struct addr_node { + uintptr_t start; + uintptr_t end; + struct addr_node *next; + struct addr_node *prev; + uint8_t is_alloc; + uint8_t is_bss; +}; + +#define BOOTSTRAP_BSS_NODES 16 +static uint8_t bss_nodes = 0; +static struct addr_node nodes[BOOTSTRAP_BSS_NODES]; + +static struct addr_node *start_node; + +static struct addr_node *alloc_node(void) { + if (bss_nodes >= BOOTSTRAP_BSS_NODES) { + //FIXME: alloc on heap + } else { + struct addr_node *node = &nodes[bss_nodes]; + bss_nodes += 1; + node->is_bss = false; + return node; + } + return NULL; +} + +static void free_node(struct addr_node *node) { + if (!node->is_bss) + free(node); +} + +void virtaddr_init(void) { + struct addr_node init = { + .start = 0, + .end = UINT64_MAX, + .next = NULL, + .prev = NULL, + .is_alloc = false, + .is_bss = true, + }; + nodes[0] = init; + start_node = &nodes[0]; + bss_nodes++; +} + +void *virtaddr_alloc(int n_pages) { + + long n_length = n_pages * PAGE_SIZE; + struct addr_node *node = start_node; + + for (; node != NULL ; node = node->next) { + + if (node->is_alloc) + continue; + + long length = node->end - node->start; + if (length >= n_length) { + struct addr_node *new = alloc_node(); + if (node == NULL) + return NULL; + new->next = node; + node->prev = new; + if (node->prev != NULL) { + node->prev->next = new; + } + new->start = node->start; + new->end = new->start + n_length; + node->start = new->end; + new->is_alloc = true; + return (void *) new->start; + } + } + + return NULL; +} + +static void merge_back(struct addr_node *node) { + while(node->prev && !node->is_alloc) { + struct addr_node *temp = node->prev; + node->start = node->prev->start; + node->prev = node->prev->prev; + free_node(temp); + } + if (node->prev == NULL) { + start_node = node; + } +} + +static void merge_forward(struct addr_node *node) { + while(node->next && !node->is_alloc) { + struct addr_node *temp = node->next; + node->end = node->next->end; + node->next = node->next->next; + free_node(temp); + } +} + +long virtaddr_free(void *virtaddr) { + + uintptr_t virt = (uintptr_t) virtaddr; + + if (virt % PAGE_SIZE) + return -1; // not page aligned, we did not give this out!!! + + struct addr_node *node = start_node; + + for (; node != NULL; node = node->next) { + if (node->start == virt) { + int length = node->end - node->start; + int pages = length / PAGE_SIZE; + merge_back(node); + merge_forward(node); + return pages; + } + } + + return -1; +}