From e7328507912e3621a97794563f8ad6c4aab84e4f Mon Sep 17 00:00:00 2001 From: Furkan Mudanyali Date: Mon, 25 Jul 2022 02:09:15 +0300 Subject: [PATCH] Finally a working paging and heap, missing copyright headers added --- README.md | 4 +- kernel/Makefile | 2 + kernel/arch/i386/boot/gdt.c | 1 + kernel/arch/i386/boot/idt.c | 1 + kernel/arch/i386/vga/tty.c | 18 ++ kernel/arch/i386/vga/vga.h | 18 ++ .../include/rockos/data_struct/sorted_array.h | 42 +++ kernel/include/rockos/kheap.h | 58 ++++ kernel/include/rockos/paging.h | 36 ++- kernel/include/rockos/rockos.h | 31 ++ kernel/rockos/data_struct/sorted_array.c | 87 ++++++ kernel/rockos/kernel.c | 42 ++- kernel/rockos/keyboard.c | 18 ++ kernel/rockos/kheap.c | 292 ++++++++++++++++++ kernel/rockos/paging.c | 192 ++++++++---- kernel/rockos/timer.c | 18 ++ 16 files changed, 777 insertions(+), 83 deletions(-) create mode 100644 kernel/include/rockos/data_struct/sorted_array.h create mode 100755 kernel/include/rockos/kheap.h mode change 100644 => 100755 kernel/include/rockos/paging.h create mode 100644 kernel/include/rockos/rockos.h create mode 100755 kernel/rockos/data_struct/sorted_array.c create mode 100755 kernel/rockos/kheap.c mode change 100644 => 100755 kernel/rockos/paging.c diff --git a/README.md b/README.md index df922b2..83be4a5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Welcome to rockOS project, a hobby OS that aims to run rogue and nethack. - PIC initialization - PIT timer - Keyboard driver -- a thing that is supposed to be paging +- Paging and Kheap ## Usage @@ -40,6 +40,8 @@ you can run qemu.sh to compile and open the OS on QEMU or iso.sh to just generat ## Acknowledgements - osdev.org community for huge documentation on OS Development - musl for libc implementation +- James Molloy for his paging and kheap tutorial +- Free Software Foundation for multiboot specification ## License diff --git a/kernel/Makefile b/kernel/Makefile index d02baa2..da37e98 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -30,6 +30,8 @@ LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) KERNEL_OBJS=\ $(KERNEL_ARCH_OBJS) \ rockos/kernel.o \ +rockos/data_struct/sorted_array.o \ +rockos/kheap.o \ rockos/paging.o \ rockos/keyboard.o \ rockos/timer.o \ diff --git a/kernel/arch/i386/boot/gdt.c b/kernel/arch/i386/boot/gdt.c index 09590aa..3a26e13 100644 --- a/kernel/arch/i386/boot/gdt.c +++ b/kernel/arch/i386/boot/gdt.c @@ -37,6 +37,7 @@ void gdt_set_descriptor(uint8_t vector, uint32_t base, uint32_t limit, uint8_t a } void gdt_init(void) { + printf("Beginning gdt initialization.\n"); gdt_set_descriptor(0, 0, 0, 0, 0); // 0x0000 Null Descriptor gdt_set_descriptor(1, 0, 0xFFFFF, 0x9A, 0xC); // 0x0008 Kernel Mode Code Segment gdt_set_descriptor(2, 0, 0xFFFFF, 0x92, 0xC); // 0x0010 Kernel Mode Data Segment diff --git a/kernel/arch/i386/boot/idt.c b/kernel/arch/i386/boot/idt.c index e776899..fa2116c 100644 --- a/kernel/arch/i386/boot/idt.c +++ b/kernel/arch/i386/boot/idt.c @@ -96,6 +96,7 @@ void idt_set_descriptor(uint8_t vector, void (*isr)(void*), uint8_t flags) { } void idt_init(void) { + printf("Beginning IDT initialization.\n"); idtptr.base = (uintptr_t)&idt[0]; idtptr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1; diff --git a/kernel/arch/i386/vga/tty.c b/kernel/arch/i386/vga/tty.c index 764e7ce..8813fe6 100644 --- a/kernel/arch/i386/vga/tty.c +++ b/kernel/arch/i386/vga/tty.c @@ -1,3 +1,21 @@ +/** + * TTY section header of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include #include diff --git a/kernel/arch/i386/vga/vga.h b/kernel/arch/i386/vga/vga.h index ff82c19..d40e571 100644 --- a/kernel/arch/i386/vga/vga.h +++ b/kernel/arch/i386/vga/vga.h @@ -1,3 +1,21 @@ +/** + * VGA section header of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef ARCH_I386_VGA_H #define ARCH_I386_VGA_H diff --git a/kernel/include/rockos/data_struct/sorted_array.h b/kernel/include/rockos/data_struct/sorted_array.h new file mode 100644 index 0000000..fed9342 --- /dev/null +++ b/kernel/include/rockos/data_struct/sorted_array.h @@ -0,0 +1,42 @@ +/** + * Sorted array data structure header of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ROCKOS_ORDERED_ARRAY_H +#define _ROCKOS_ORDERED_ARRAY_H + +#include + +typedef char (*LessThan)(void*, void*); + +typedef struct { + void** data; + uint32_t size; + uint32_t max_size; + LessThan less_than; +} SortedArray; + +char less_than(void*, void*); + +SortedArray SortedArrayCreate(uint32_t, LessThan); +SortedArray SortedArrayPlace(void*, uint32_t, LessThan); +void SortedArrayDestroy(SortedArray*); +void SortedArrayInsert(void*, SortedArray*); +void* SortedArraySearch(uint32_t, SortedArray*); +void SortedArrayDelete(uint32_t, SortedArray*); + +#endif \ No newline at end of file diff --git a/kernel/include/rockos/kheap.h b/kernel/include/rockos/kheap.h new file mode 100755 index 0000000..da9b0df --- /dev/null +++ b/kernel/include/rockos/kheap.h @@ -0,0 +1,58 @@ +/** + * KHeap section header of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ROCKOS_KHEAP_H +#define _ROCKOS_KHEAP_H + +#include +#include + +#define KHEAP_START 0xC0000000 +#define KHEAP_INITIAL_SIZE 0x100000 +#define HEAP_INDEX_SIZE 0x20000 +#define HEAP_MAGIC 0x06163474 +#define HEAP_MIN_SIZE 0x70000 + +typedef struct { + uint32_t magic; + uint8_t hole; + uint32_t size; +} Header; + +typedef struct { + uint32_t magic; + Header* header; +} Footer; + +typedef struct { + SortedArray index; + uint32_t addr_start; + uint32_t addr_end; + uint32_t addr_max; + uint8_t supervisor; + uint8_t readonly; +} Heap; + +Heap* HeapCreate(uint32_t, uint32_t, uint32_t, uint8_t, uint8_t); +void* alloc(uint32_t, uint8_t, Heap*); +void free(void*, Heap*); +uint32_t kmalloc_int(uint32_t, uint8_t, uint32_t*); +uint32_t kmalloc(uint32_t); +void kfree(void*); + +#endif \ No newline at end of file diff --git a/kernel/include/rockos/paging.h b/kernel/include/rockos/paging.h old mode 100644 new mode 100755 index e381529..e817a33 --- a/kernel/include/rockos/paging.h +++ b/kernel/include/rockos/paging.h @@ -16,15 +16,39 @@ * along with this program. If not, see . */ -#include -#include - #ifndef _ROCKOS_PAGING_H #define _ROCKOS_PAGING_H -#define PAGE_ENTRIES 1024 -#define PAGE_SIZE 4096 +#include -void alloc_pages(uint32_t*, size_t); +typedef struct { + uint32_t present: 1; + uint32_t rw: 1; + uint32_t user: 1; + uint32_t accessed: 1; + uint32_t dirty: 1; + uint32_t unused: 7; + uint32_t frame: 20; +} Page; + +typedef struct { + Page pages[1024]; +} PageTable; + +typedef struct { + PageTable* tables[1024]; + uint32_t tablesPhys[1024]; + uint32_t physAddr; +} PageDirectory; + +void paging_init(); +void paging_switch_dir(PageDirectory*); +Page* PageGet(uint32_t, int32_t, PageDirectory*); +void FrameSet(uint32_t); +void FrameClear(uint32_t); +uint32_t FrameTest(uint32_t); +uint32_t FrameFirst(); +void FrameFree(Page*); +void FrameAlloc(Page*, char, char); #endif \ No newline at end of file diff --git a/kernel/include/rockos/rockos.h b/kernel/include/rockos/rockos.h new file mode 100644 index 0000000..6fdd441 --- /dev/null +++ b/kernel/include/rockos/rockos.h @@ -0,0 +1,31 @@ +/** + * Header of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +static inline void panic(char* str) { + printf("%s\n", str); + asm("cli;hlt"); +} + +static inline void assert(uint32_t val) { + if(!val) { + panic("ASSERTION FAILED!"); + } +} \ No newline at end of file diff --git a/kernel/rockos/data_struct/sorted_array.c b/kernel/rockos/data_struct/sorted_array.c new file mode 100755 index 0000000..2ad17d5 --- /dev/null +++ b/kernel/rockos/data_struct/sorted_array.c @@ -0,0 +1,87 @@ +/** + * Sorted array data structure of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +char less_than(void* a, void* b) { + return a < b; +} + +SortedArray SortedArrayCreate(uint32_t size, LessThan less) { + SortedArray myArray = { + .data = (void*)kmalloc(size * sizeof(void*)), + .size = 0, + .max_size = size, + .less_than = less, + }; + memset(myArray.data, 0, size * sizeof(void*)); + return myArray; +} + +SortedArray SortedArrayPlace(void* address, uint32_t size, LessThan less) { + SortedArray myArray = { + .data = (void**)address, + .size = 0, + .max_size = size, + .less_than = less, + }; + memset(myArray.data, 0, size * sizeof(void*)); + return myArray; +} + +void SortedArrayDestroy(SortedArray* myArray) { + kfree(myArray->data); +} + +void SortedArrayInsert(void* element, SortedArray* myArray) { + assert((uint32_t)myArray->less_than); + uint32_t iter = 0; + while(iter < myArray->size && myArray->less_than(myArray->data[iter], element)) { + ++iter; + } + if(myArray->size == iter) { + myArray->data[myArray->size++] = element; + } else { + void* temp = myArray->data[iter]; + myArray->data[iter] = element; + while(iter < myArray->size) { + ++iter; + void* temp2 = myArray->data[iter]; + myArray->data[iter] = temp; + temp = temp2; + } + myArray->size++; + } +} + +void* SortedArraySearch(uint32_t index, SortedArray* myArray) { + assert(index < myArray->size); + return myArray->data[index]; +} + +void SortedArrayDelete(uint32_t index, SortedArray* myArray) { + assert(index < myArray->size); + while (index < myArray->size) { + myArray->data[index] = myArray->data[index + 1]; + ++index; + } + myArray->size--; +} \ No newline at end of file diff --git a/kernel/rockos/kernel.c b/kernel/rockos/kernel.c index 62f9720..28849f3 100644 --- a/kernel/rockos/kernel.c +++ b/kernel/rockos/kernel.c @@ -1,23 +1,37 @@ -#include +/** + * Entry point of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include #include #include #include #include #include #include +#include #include +#include #include extern char _rockos_start, _rockos_end; static multiboot_info_t* multiboot_info; -void panic(char* str) { - printf("%s\n", str); - asm("cli;hlt"); -} - void bootloader_init(multiboot_info_t* mbd, unsigned int magic) { /* Make sure the magic number matches for memory mapping*/ if(magic != MULTIBOOT_BOOTLOADER_MAGIC) { @@ -65,13 +79,15 @@ void kernel_main() { // } } - uint32_t* pages; - alloc_pages(pages, 1); - printf("Page Start: %#08X\n", *pages); - alloc_pages(*pages, 8192); - for(int i = 0; i < 8192; ++i){ - //printf("Page Start: %#08X\n", (uint32_t)(*pages + i)); - } + + uint32_t a = kmalloc(8); + uint32_t b = kmalloc(8); + uint32_t c = kmalloc(8); + printf("A: %#08X B: %#08X C: %#08X\n",a,b,c); + kfree(c); + kfree(b); + uint32_t d = kmalloc(8); + printf("D: %#08X\n", d); unsigned char key; for(;;) { diff --git a/kernel/rockos/keyboard.c b/kernel/rockos/keyboard.c index 9f2089e..80e0c8f 100644 --- a/kernel/rockos/keyboard.c +++ b/kernel/rockos/keyboard.c @@ -1,3 +1,21 @@ +/** + * Keyboard driver of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include #include diff --git a/kernel/rockos/kheap.c b/kernel/rockos/kheap.c new file mode 100755 index 0000000..97242eb --- /dev/null +++ b/kernel/rockos/kheap.c @@ -0,0 +1,292 @@ +/** + * KHeap section of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +extern char _rockos_end; +uint32_t start_addr = (uint32_t)&_rockos_end; +extern PageDirectory* kernel_dir; +Heap* kheap = 0; + +static int32_t smallest_hole(uint32_t size, uint8_t aligned, Heap* heap) { + uint32_t i = 0; + while(i < heap->index.size) { + Header* header = (Header*)SortedArraySearch(i, &heap->index); + if(aligned) { + uint32_t location = (uint32_t)header; + uint32_t offset = 0; + if((location + sizeof(Header) & ~0xFFF) != 0) { + offset = 0x1000 - (location + sizeof(Header)) % 0x1000; + } + uint32_t hole_size = (uint32_t)header->size - offset; + if(hole_size >= (uint32_t)size) { + break; + } + } else if (header->size >= size) { + break; + } + i++; + } + if(i == heap->index.size) { + return -1; + } + return i; +} + +static void expand(uint32_t size, Heap* heap) { + assert(size > heap->addr_end - heap->addr_start); + if((size & ~0xFFF) != 0) { + size &= ~0xFFF; + size += 0x1000; + } + assert(heap->addr_start + size <= heap->addr_max); + uint32_t size_old = heap->addr_end - heap->addr_start; + for(uint32_t i = size_old; i < size; i+= 0x1000) { + FrameAlloc( PageGet(heap->addr_start + i, 1, kernel_dir), heap->supervisor, heap->readonly ); + } + heap->addr_end = heap->addr_start + size; +} + +static uint32_t shrink(uint32_t size, Heap* heap) { + assert(size < heap->addr_end - heap->addr_start); + if(size & 0x1000) { + size &= 0x1000; + size += 0x1000; + } + if(size < HEAP_MIN_SIZE) { + size = HEAP_MIN_SIZE; + } + + uint32_t size_old = heap->addr_end - heap->addr_start; + for(uint32_t i = size_old - 0x1000; size < i; i -= 0x1000) { + FrameFree(PageGet(heap->addr_start + i, 0, kernel_dir)); + } + + heap->addr_end = heap->addr_start + size; + return size; +} + +void* alloc(uint32_t size, uint8_t aligned, Heap* heap) { + uint32_t size_new = size + sizeof(Header) + sizeof(Footer); + int32_t iter = smallest_hole(size_new, aligned, heap); + if(iter == -1) { + uint32_t len_old = heap->addr_end - heap->addr_start; + uint32_t end_old_addr = heap->addr_end; + expand(len_old + size_new, heap); + uint32_t len_new = heap->addr_end - heap->addr_start; + iter = 0; + uint32_t idx = -1; + uint32_t val = 0; + while((uint32_t)iter < heap->index.size) { + uint32_t temp = (uint32_t)SortedArraySearch(iter, &heap->index); + if (temp > val) { + val = temp; + idx = iter; + } + ++iter; + } + + if(idx == -1) { + Header* header = (Header*)end_old_addr; + header->magic = HEAP_MAGIC; + header->size = len_new - len_old; + header->hole = 1; + Footer* footer = (Footer*)(end_old_addr + header->size - sizeof(Footer)); + footer->magic = HEAP_MAGIC; + footer->header = header; + SortedArrayInsert((void*)header, &heap->index); + } else { + Header* header = SortedArraySearch(idx, &heap->index); + header->size += len_new - len_old; + Footer* footer = (Footer*)((uint32_t)header + header->size - sizeof(Footer)); + footer->magic = HEAP_MAGIC; + footer->header = header; + } + return alloc(size, aligned, heap); + } + + Header* hole_header_old = (Header*)SortedArraySearch(iter, &heap->index); + uint32_t hole_pos_old = (uint32_t)hole_header_old; + uint32_t hole_size_old = hole_header_old->size; + + if(hole_size_old - size_new < sizeof(Header) + sizeof(Footer)) { + size += hole_size_old - size_new; + size_new = hole_size_old; + } + + if(aligned && (hole_pos_old & ~0xFFF)) { + uint32_t location_new = hole_pos_old + 0x1000 - (hole_pos_old & 0xFFF) - sizeof(Header); + Header* hole_header = (Header*) hole_pos_old; + hole_header->size = 0x1000 - (hole_pos_old & 0xFFF) - sizeof(Header); + hole_header->magic = HEAP_MAGIC; + hole_header->hole = 1; + Footer* hole_footer = (Footer*)((uint32_t)location_new - sizeof(Footer)); + hole_footer->magic = HEAP_MAGIC; + hole_footer->header = hole_header; + hole_pos_old = location_new; + hole_size_old -= hole_header->size; + } else { + SortedArrayDelete(iter, &heap->index); + } + + Header* block_header = (Header*)hole_pos_old; + block_header->magic = HEAP_MAGIC; + block_header->hole = 0; + block_header->size = size_new; + Footer* block_footer = (Footer*)(hole_pos_old + sizeof(Header) + size); + block_footer->magic = HEAP_MAGIC; + block_footer->header = block_header; + + if(hole_size_old - size_new) { + Header* hole_header = (Header*)(hole_pos_old + sizeof(Header) + size + sizeof(Footer)); + hole_header->magic = HEAP_MAGIC; + hole_header->hole = 1; + hole_header->size = hole_size_old - size_new; + Footer* hole_footer = (Footer*)((uint32_t)hole_header + hole_size_old - size_new - sizeof(Footer)); + if ((uint32_t)hole_footer < heap->addr_end) { + hole_footer->magic = HEAP_MAGIC; + hole_footer->header = hole_header; + } + SortedArrayInsert((void*)hole_header, &heap->index); + } + return (void*)((uint32_t)block_header + sizeof(Header)); +} + +void free(void* pointer, Heap* heap) { + if(pointer == 0) + return; + + Header* header = (Header*)((uint32_t)pointer - sizeof(Header)); + Footer* footer = (Footer*)((uint32_t)header + header->size - sizeof(Footer)); + + assert(header->magic == HEAP_MAGIC); + assert(footer->magic == HEAP_MAGIC); + + header->hole = 1; + char add = 1; + + Footer* temp_footer = (Footer*)((uint32_t)header - sizeof(Footer)); + if(temp_footer->magic == HEAP_MAGIC && temp_footer->header->hole) { + uint32_t cache_size = header->size; + header = temp_footer->header; + footer->header = header; + header->size += cache_size; + add = 0; + } + + Header* temp_header = (Header*)((uint32_t)footer + sizeof(footer)); + if(temp_header->magic == HEAP_MAGIC && temp_header->hole) { + header->size += temp_header->size; + temp_footer = (Footer*)((uint32_t)temp_header + temp_header->size - sizeof(Footer)); + footer = temp_footer; + uint32_t iter = 0; + while((iter < heap->index.size) && (SortedArraySearch(iter, &heap->index) != (void*)temp_header)) { + ++iter; + } + assert(iter < heap->index.size); + SortedArrayDelete(iter, &heap->index); + } + + if((uint32_t)footer + sizeof(Footer) == heap->addr_end) { + uint32_t len_old = heap->addr_end - heap->addr_start; + uint32_t len_new = shrink((uint32_t)header - heap->addr_start, heap); + if(header->size - (len_old - len_new) > 0) { + header->size -= len_old - len_new; + footer = (Footer*)((uint32_t)header + header->size - sizeof(Footer)); + footer->magic = HEAP_MAGIC; + footer->header = header; + } else { + uint32_t iter = 0; + while((iter < heap->index.size) && (SortedArraySearch(iter, &heap->index) != (void*)temp_header)) { + ++iter; + } + if(iter < heap->index.size) { + SortedArrayDelete(iter, &heap->index); + } + } + } + + if(add) { + SortedArrayInsert((void*)header, &heap->index); + } +} + +uint32_t kmalloc_int(uint32_t size, uint8_t aligned, uint32_t* phys_addr) { + if(kheap) { + void* addr = alloc(size, aligned, kheap); + if (phys_addr) { + Page* page = PageGet((uint32_t)addr, 0, kernel_dir); + *phys_addr = (page->frame * 0x1000) + ((uint32_t)addr & 0xFFF); + } + return (uint32_t)addr; + } + if(aligned && (start_addr & 0xFFF)) { + start_addr &= ~0xFFF; + start_addr += 0x1000; + } + if(phys_addr) { + *phys_addr = start_addr; + } + uint32_t temp = start_addr; + start_addr += size; + return temp; +} + +uint32_t kmalloc(uint32_t size) { + return kmalloc_int(size, 0, 0); +} + +void kfree(void* pointer) { + free(pointer, kheap); +} + +static char HeaderLessThan(void* a, void* b) { + return ((Header*)a)->size < ((Header*)b)->size; +} + +Heap* HeapCreate(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly) { + Heap* heap = (Heap*)kmalloc(sizeof(Heap)); + + assert(start % 0x1000 == 0); + assert(end % 0x1000 == 0); + + heap->index = SortedArrayPlace((void*)start, HEAP_INDEX_SIZE, &HeaderLessThan); + start += sizeof(void*) * HEAP_INDEX_SIZE; + + if(start & ~0xFFF) { + start &= ~0xFFF; + start += 0x1000; + } + + heap->addr_start = start; + heap->addr_end = end; + heap->addr_max = max; + heap->supervisor = supervisor; + heap->readonly = readonly; + + Header* hole = (Header*)start; + hole->size = end - start; + hole->magic = HEAP_MAGIC; + hole->hole = 1; + SortedArrayInsert((void*)hole, &heap->index); + + return heap; +} \ No newline at end of file diff --git a/kernel/rockos/paging.c b/kernel/rockos/paging.c old mode 100644 new mode 100755 index a6e1f1e..5983dcb --- a/kernel/rockos/paging.c +++ b/kernel/rockos/paging.c @@ -1,76 +1,142 @@ +/** + * Paging section of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include -#include -#include -#include +#include +#include +#include -void load_page_dir(uint32_t* page_dir) { - asm volatile ( - "mov %%eax, %%cr3" - : - : "a"(page_dir) - : "memory" - ); +#define INDEX_FROM_BIT(x) (x/(8*4)) +#define OFFSET_FROM_BIT(x) (x%(8*4)) + +PageDirectory* kernel_dir = 0; +PageDirectory* current_dir = 0; + +uint32_t* frames; +uint32_t nframes; + +extern uint32_t start_addr; +extern Heap* kheap; + +void FrameSet(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + frames[INDEX_FROM_BIT(frame)] |= (1 << OFFSET_FROM_BIT(frame)); } -void enable_paging() { - asm volatile ( - "mov %cr0, %eax\n" - "or $0x80000000, %eax\n" - "mov %eax, %cr0" - ); +void FrameClear(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + frames[INDEX_FROM_BIT(frame)] &= ~(1 << OFFSET_FROM_BIT(frame)); } -extern char _rockos_end; -static uint32_t* page_dir __attribute__((packed)); - -void paging_init() { - page_dir = (uint32_t*)(((uint32_t)&_rockos_end & ~0xFFF) + 0x1000); - for(int i = 0; i < PAGE_ENTRIES; i++) { - // Supervisor: only kernel-mode can access - // Write Enabled: Can be both read and written to - // Not Present: Page table not present - *(page_dir + i) = 0x00000002; - } - - uint32_t* firstPageTable __attribute__((packed)) = (uint32_t*)(((uint32_t)page_dir & ~0xFFF) + 0x1000); - for(unsigned int i = 0; i < PAGE_ENTRIES; i++) { - // As the address is page aligned, it will leave 12 bits zeroed, - // which are used by the attributes. - firstPageTable[i] = (i*0x1000) | 0x003; // attr: supervisor, r/w, present, 9th bit set - } - - page_dir[0] = (uint32_t)firstPageTable | 0x003; //attr: supervisor, r/w, present - load_page_dir(page_dir); - enable_paging(); +uint32_t FrameTest(uint32_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + return (frames[INDEX_FROM_BIT(frame)] & (1 << OFFSET_FROM_BIT(frame))); } -void alloc_pages(uint32_t* pages, size_t size) { - for(size_t i = 0; i < size;) { - for(size_t j = 0; j < PAGE_ENTRIES && i < size; ++j) { - printf("oklahoma %#08X\n", page_dir[j]); - if((page_dir[j] & 3) == 3) { - uint32_t* pageTable __attribute__((packed)) = page_dir[j] & ~0xFFF; - for(int k = 0; k < PAGE_ENTRIES && i < size; ++k) { - if((pageTable[k] & 3) == 3 && (pageTable[k] & 0x100) != 0x100) { - pageTable[k] |= 0x100; - pages[i] = ((uint32_t)pageTable & ~0xFFF) | (pageTable[k] >> 12); - printf("connecticut %#08X\n", pages[i]); - ++i; - } +uint32_t FrameFirst() { + for(uint32_t i = 0; i < INDEX_FROM_BIT(nframes); ++i) { + if(frames[i] != 0xFFFFFFFF) { + for(uint32_t j = 0; j < 32; ++j) { + uint32_t test = 1 << j; + if(!(frames[i]&test)) { + return i*4*8 + j; } - } else { - printf("aa %#08X\n", (page_dir[j-1] & ~0xFFF) + 0x4000); - uint32_t* newPageTable __attribute__((packed)) = (page_dir[j-1] & ~0xFFF) + 0x4000; - printf("alabama %#08X, %#08X\n", newPageTable[0], (page_dir[j-1] & ~0xFFF) + 0x4000); - for(unsigned int l = 0; l < PAGE_ENTRIES; l++) { - // As the address is page aligned, it will leave 12 bits zeroed, - // which are used by the attributes. - newPageTable[l] = (l*0x1000) | 0x003; // attr: supervisor, r/w, present, 9th bit set - } - page_dir[j] = (uint32_t)newPageTable | 0x003; - printf("NewPageTable: %#08X\n", page_dir[j]); - --j; } } } + return 0; +} + +void FrameAlloc(Page* page, char kernel, char writeable) { + if (page->frame) { + return; + } + uint32_t i = FrameFirst(); + if(i == (uint32_t)-1) { + panic("NO FREE FRAMES LEFT!"); + } + FrameSet(i * 0x1000); + page->present = 1; + page->rw = writeable; + page->user = !kernel; + page->frame = i; +} + +void FrameFree(Page* page) { + uint32_t frame; + if(!(frame = page->frame)) { + return; + } + FrameClear(frame); + page->frame = 0; +} + +Page* PageGet(uint32_t addr, int32_t make, PageDirectory* dir) { + addr /= 0x1000; + uint32_t table_i = addr / 1024; + if(dir->tables[table_i]) { + return &dir->tables[table_i]->pages[addr%1024]; + } + + if(make) { + uint32_t temp; + dir->tables[table_i] = (PageTable*)kmalloc_int(sizeof(PageTable), 1, &temp); + memset(dir->tables[table_i], 0, 0x1000); + dir->tablesPhys[table_i] = temp | 0x7; + return &dir->tables[table_i]->pages[addr%1024]; + } + + return 0; +} + +void paging_switch_dir(PageDirectory* dir) { + current_dir = dir; + asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhys)); + uint32_t cr0; + asm volatile("mov %%cr0, %0": "=r"(cr0)); + cr0 |= 0x80000000; + asm volatile("mov %0, %%cr0":: "r"(cr0)); +} + +void paging_init() { + printf("Initializing paging.\n"); + uint32_t page_end_mem = 0x1000000; + nframes = page_end_mem / 0x1000; + + frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes)); + memset(frames, 0, INDEX_FROM_BIT(nframes)); + + kernel_dir = (PageDirectory*)kmalloc_int(sizeof(PageDirectory), 1, 0); + memset(kernel_dir, 0, sizeof(PageDirectory)); + current_dir = kernel_dir; + + for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) { + PageGet(i, 1, kernel_dir); + } + + for(uint32_t i = 0; i < start_addr + 0x1000; i += 0x1000) { + FrameAlloc(PageGet(i, 1, kernel_dir), 0, 0); + } + + for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) { + FrameAlloc(PageGet(i, 1, kernel_dir), 0, 0); + } + + paging_switch_dir(kernel_dir); + kheap = HeapCreate(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); } \ No newline at end of file diff --git a/kernel/rockos/timer.c b/kernel/rockos/timer.c index 63f1e98..3f07c65 100644 --- a/kernel/rockos/timer.c +++ b/kernel/rockos/timer.c @@ -1,3 +1,21 @@ +/** + * PIT section of rockOS + * Copyright (C) 2022 Furkan Mudanyali + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, _either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include #include