KraKern

C++ Kernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/KraKern

commit dc7f9fa1c342b799782bca1d04750e45de8af5b4
parent 415a1c215f8fdc87489558726ac281ee61bb0482
Author: Ne02ptzero <louis@ne02ptzero.me>
Date:   Wed, 13 Jan 2016 23:17:11 +0100

Add(Memory): Full virtual memory support.

Diffstat:
Mincludes/core/Io.hpp | 1+
Mincludes/core/Kernel.hpp | 5++++-
Aincludes/core/Memory.hpp | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aincludes/core/list.hpp | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mkern.img | 0
Mkernel/Io.cpp | 11+++++++++++
Mkernel/Kernel.cpp | 13++++++++-----
Mkernel/Makefile | 2+-
Akernel/Memory.cpp | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mkernel/main.cpp | 3+--
10 files changed, 316 insertions(+), 9 deletions(-)

diff --git a/includes/core/Io.hpp b/includes/core/Io.hpp @@ -59,6 +59,7 @@ class Io { void load_screen(void); void loading(const char *); void done(void); + void panic(const char *s); enum console_type { BUFFERED, diff --git a/includes/core/Kernel.hpp b/includes/core/Kernel.hpp @@ -1,20 +1,23 @@ #ifndef __KERNEL__ # define __KERNEL__ # include <os.h> +# include <boot.h> # include <x86.hpp> # include <Io.hpp> +# include <Memory.hpp> class Kernel { public: Kernel(void); - void init(void); + void init(multiboot_info *mbi); void welcome(void); Io io; GDT gdt; IDT idt; + Memory mem; }; #endif diff --git a/includes/core/Memory.hpp b/includes/core/Memory.hpp @@ -0,0 +1,84 @@ +#ifndef __MEMORY__ +# define __MEMORY__ + +# include <list.hpp> +# include <os.h> + +// Memory defines + +# define PAGE(addr) addr >> 12 +# define PAGESIZE 4096 +# define RAM_MAXSIZE 0x100000000 +# define RAM_MAXPAGE 0x100000 +# define PAGING_FLAG 0x80000000 +# define PSE_FLAG 0x00000010 +# define PG_PRESENT 0x00000001 +# define PG_WRITE 0x00000002 +# define PG_USER 0x00000004 +# define PG_4MB 0x00000080 +# define KERN_PDIR 0x00001000 +# define KERN_STACK 0x0009FFF0 +# define KERN_BASE 0x00100000 +# define KERN_PG_HEAP 0x00800000 +# define KERN_PG_HEAP_LIM 0x10000000 +# define KERN_HEAP 0x10000000 +# define KERN_HEAP_LIM 0x40000000 +# define USER_OFFSET 0x40000000 +# define USER_STACK 0xE0000000 +# define KERN_PG_1 0x400000 +# define KERN_PG_1_LIM 0x800000 +# define VADDR_PD_OFFSET(addr) ((addr) & 0xFFC00000) >> 22 +# define VADDR_PT_OFFSET(addr) ((addr) & 0x003FF000) >> 12 +# define VADDR_PG_OFFSET(addr) (addr) & 0x00000FFF +# define KMALLOC_MINSIZE 16 + +// Memory structures + +struct page { + char *v_addr; + char *p_addr; + list_head list; +}; + +struct page_directory { + page *base; + list_head pt; +}; + +struct vm_area { + char *vm_start; + char *vm_end; + list_head list; +}; + +struct kmalloc_header { + unsigned long size:31; + unsigned long used:1; +} __attribute ((packed)); + +class Memory { + public: + void init(u32 hm); + void *ksbrk(int n); + void *kmalloc(unsigned long size); + void kfree(void *v_addr); + u32 ksize(void *v_addr); + + private: + void _init_memory(u32 hm); + char *_get_page_frame(void); + int _pd0_add_page(char *v_addr, char *p_addr, int flags); + + char *_kern_heap; + list_head _kern_free_vm; + u32 *_pd0; + char *_pg0; + char *_pg1; + char *_pg1_end; + u8 _mem_bitmap[RAM_MAXPAGE / 8]; + u32 _kmalloc_used; +}; + +# include <Kernel.hpp> + +#endif diff --git a/includes/core/list.hpp b/includes/core/list.hpp @@ -0,0 +1,49 @@ +#ifndef __LIST__ +# define __LIST__ + +// List helpers. +# define LIST_HEAD_INIT(name) { &(name), &(name) } +# define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) +#define list_entry(ptr, type, member) \ + (type*) ((char*) ptr - (char*) &((type*)0)->member) +#define list_first_entry(head, type, member) \ + list_entry((head)->next, type, member) +#define list_for_each(p, head) \ + for (p = (head)->next; p != (head); p = p->next) +#define list_for_each_safe(p, n, head) \ + for (p = (head)->next, n = p->next; p != (head); p = n, n = n->next) +#define list_for_each_entry(p, head, member) \ + for (p = list_entry((head)->next, typeof(*p), member); \ + &p->member != (head); \ + p = list_entry(p->member.next, typeof(*p), member)) + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +static inline void INIT_LIST_HEAD(struct list_head *list) { + list->next = list; + list->prev = list; +} + +static inline void list_add(struct list_head *neww, struct list_head *head) { + neww->next = head->next; + neww->prev = head; + (head->next)->prev = neww; + head->next = neww; +} + +static inline void list_del(struct list_head *p) { + (p->next)->prev = p->prev; + (p->prev)->next = p->next; + p->next = 0; + p->prev = 0; +} + +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +#endif diff --git a/kern.img b/kern.img Binary files differ. diff --git a/kernel/Io.cpp b/kernel/Io.cpp @@ -137,6 +137,17 @@ void Io::done(void) { this->puts("]\n"); } +void Io::panic(const char *s) { + this->puts("[ "); + this->set_color(COLOR_RED); + this->puts("PANIC"); + this->set_color(COLOR_WHITE); + this->puts(" ]: "); + this->puts(s); + asm("hlt"); + // Reboot +} + // Output void Io::obyte(u32 a, u8 v) { asmv("outb %%al, %%dx" :: "d" (a), "a" (v));; }; void Io::oword(u32 a, u16 v) { asmv("outw %%ax, %%dx" :: "d" (a), "a" (v));; }; diff --git a/kernel/Kernel.cpp b/kernel/Kernel.cpp @@ -1,22 +1,25 @@ #include <Kernel.hpp> -extern Io __io; -extern GDT __gdt; -extern IDT __idt; -Kernel __kern; +extern Io __io; +extern GDT __gdt; +extern IDT __idt; +extern Memory __mem; +Kernel __kern; Kernel::Kernel(void) { } -void Kernel::init(void) { +void Kernel::init(multiboot_info *mbi) { this->io = __io; this->gdt = __gdt; this->idt = __idt; + this->mem = __mem; this->io.init(); this->welcome(); this->gdt.init(); this->idt.init(); + this->mem.init(mbi->high_mem); } void Kernel::welcome(void) { diff --git a/kernel/Makefile b/kernel/Makefile @@ -1 +1 @@ -OBJS += kernel/main.o kernel/Io.o kernel/Kernel.o +OBJS += kernel/main.o kernel/Io.o kernel/Kernel.o kernel/Memory.o diff --git a/kernel/Memory.cpp b/kernel/Memory.cpp @@ -0,0 +1,157 @@ +# include <Memory.hpp> + +Memory __mem; + +void Memory::init(u32 hm) { + this->_pd0 = (u32 *)KERN_PDIR; + this->_pg0 = (char *)0x0; + this->_pg1 = (char *)KERN_PG_1; + this->_pg1_end = (char *)KERN_PG_1_LIM; + this->_kmalloc_used = 0; + + __kern.io.loading("Memory ..."); + this->_init_memory(hm); + __kern.io.done(); +} + +void Memory::_init_memory(u32 hm) { + int pg, pg_limit; + unsigned long i; + struct vm_area *p, *pm; + + pg_limit = (hm * 1024) / PAGESIZE; + for (pg = 0; pg < pg_limit / 8; pg++) + this->_mem_bitmap[pg] = 0x0; + for (pg = pg_limit / 8; pg < RAM_MAXPAGE; pg++) + this->_mem_bitmap[pg] = 0xFF; + for (pg = PAGE(0x0); pg < PAGE((u32)this->_pg1_end); pg++) + this->_mem_bitmap[((u32)pg) / 8] |= (1 << (((u32)pg) % 8)); + this->_pd0[0] = ((u32) this->_pg0 | (PG_PRESENT | PG_WRITE | PG_4MB)); + this->_pd0[1] = ((u32) this->_pg1 | (PG_PRESENT | PG_WRITE | PG_4MB)); + for (i = 2; i < 1023; i++) + this->_pd0[i] = ((u32)this->_pg1 + PAGESIZE * i) | (PG_PRESENT | PG_WRITE); + this->_pd0[1023] = ((u32)this->_pd0 | (PG_PRESENT | PG_WRITE)); + asm(" mov %0, %%eax \n \ + mov %%eax, %%cr3 \n \ + mov %%cr4, %%eax \n \ + or %2, %%eax \n \ + mov %%eax, %%cr4 \n \ + mov %%cr0, %%eax \n \ + or %1, %%eax \n \ + mov %%eax, %%cr0"::"m"(this->_pd0), "i"(PAGING_FLAG), "i"(PSE_FLAG)); + this->_kern_heap = (char *)KERN_HEAP; + this->ksbrk(1); + p = (struct vm_area *)this->kmalloc(sizeof(struct vm_area)); + p->vm_start = (char *)KERN_PG_HEAP; + p->vm_end = (char *)KERN_PG_HEAP_LIM; + INIT_LIST_HEAD(&this->_kern_free_vm); + list_add(&p->list, &this->_kern_free_vm); +} + +void *Memory::ksbrk(int n) { + struct kmalloc_header *chunk; + char *p_addr; + + if ((this->_kern_heap + (n * PAGESIZE)) > (char *)KERN_HEAP_LIM) + __kern.io.panic("ksbrk(): No virtual memory left !"); + chunk = (struct kmalloc_header *)this->_kern_heap; + for (int i = 0; i < n; i++) { + p_addr = this->_get_page_frame(); + if ((int)(p_addr) < 0) + __kern.io.panic("ksbrk(): No free page available !"); + this->_pd0_add_page(this->_kern_heap, p_addr, 0); + this->_kern_heap += PAGESIZE; + } + chunk->size = PAGESIZE * n; + chunk->used = 0; + return chunk; +} + +void *Memory::kmalloc(unsigned long size) { + unsigned long realsize; + struct kmalloc_header *chunk, *other; + + if (size <= 0) + return 0; + + if ((realsize = sizeof(struct kmalloc_header) + size) < KMALLOC_MINSIZE) + realsize = KMALLOC_MINSIZE; + chunk = (struct kmalloc_header *)KERN_HEAP; + while (chunk->used || chunk->size < realsize) { + if (chunk->size == 0) + __kern.io.panic("kmalloc(): Corrupted chunk with null size"); + chunk = (struct kmalloc_header *)((char *)chunk + chunk->size); + if (chunk == (struct kmalloc_header *)this->_kern_heap) { + if ((int)(ksbrk((realsize / PAGESIZE) + 1)) < 0) + __kern.io.panic("kmalloc(): No memory left for the kernel. UNACCEPTABLE CONDITIIIION"); + else if (chunk > (struct kmalloc_header *)this->_kern_heap) + __kern.io.panic("kmalloc(): Chunk to high for heap limit"); + } + } + if (chunk->size - realsize < KMALLOC_MINSIZE) { + chunk->used = 1; + } else { + other = (struct kmalloc_header *)((char *)chunk + realsize); + other->size = chunk->size - realsize; + other->used = 0; + chunk->size = realsize; + chunk->used = 1; + } + this->_kmalloc_used += realsize; + return (char *)chunk + sizeof(struct kmalloc_header); +} + +void Memory::kfree(void *v_addr) { + struct kmalloc_header *chunk, *other; + + if (v_addr <= 0) + return ; + chunk = (struct kmalloc_header *)((u32)v_addr - sizeof(struct kmalloc_header)); + chunk->used = 0; + this->_kmalloc_used -= chunk->size; + while ((other = (struct kmalloc_header *)((char *)chunk + chunk->size)) && + other < (struct kmalloc_header *)this->_kern_heap && + other->used == 0) + chunk->size += other->size; +} + +u32 Memory::ksize(void *v_addr) { + struct kmalloc_header *chunk; + + if (v_addr <= 0) + return 0; + chunk = (struct kmalloc_header *)((u32)v_addr - sizeof(struct kmalloc_header)); + return chunk->size; +} + +char *Memory::_get_page_frame(void) { + int byte, bit, page = -1; + + for (byte = 0; byte < RAM_MAXPAGE / 8; byte++) { + if (this->_mem_bitmap[byte] != 0xFF) { + for (bit = 0; bit < 8; bit++) { + if (!(this->_mem_bitmap[byte] & (1 << bit))) { + page = 8 * byte + bit; + this->_mem_bitmap[((u32)page) / 8] |= (1 << (((u32)page) % 8)); + return (char *)(page * PAGESIZE); + } + } + } + } + return (char *)-1; +} + +int Memory::_pd0_add_page(char *v_addr, char *p_addr, int flags) { + u32 *pde, *pte; + + if (v_addr > (char *)USER_OFFSET) { + __kern.io.panic("_pd0_add_page(): Address not in kernel space"); + } + pde = (u32 *)(0xFFFFF000 | (((u32)v_addr & 0xFFC00000) >> 20)); + if (!(*pde & PG_PRESENT)) + __kern.io.panic("_pd0_add_page(): Page asked can't be found"); + pte = (u32 *)(0xFFC00000 | (((u32) v_addr & 0xFFFFF000) >> 10)); + *pte = ((u32) p_addr) | (PG_PRESENT | PG_WRITE | flags); + this->_mem_bitmap[((u32)p_addr) / 8] |= (1 << (((u32)p_addr) % 8)); + return 0; +} diff --git a/kernel/main.cpp b/kernel/main.cpp @@ -4,8 +4,7 @@ extern Kernel __kern; extern "C" void kmain(multiboot_info *info) { - (void)info; // Main class initialization - __kern.init(); + __kern.init(info); return ; }