diff --git a/Makefile b/Makefile index 809aec74..e3d7086f 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,14 @@ qemu: thor.flp qemu-kvm -cpu host -fda thor.flp bochs: thor.flp - bochs -q -f bochsrc.txt + echo "c" > commands + bochs -qf bochsrc.txt -rc commands + rm commands + +debug: thor.flp + echo "c" > commands + bochs -qf bochsrc.txt -rc commands + rm commands force_look: true diff --git a/bochsrc.txt b/bochsrc.txt index bf85b1b2..a2d1e81b 100644 --- a/bochsrc.txt +++ b/bochsrc.txt @@ -1,2 +1,4 @@ +display_library: sdl +magic_break: enabled=1 floppya: 1_44=thor.flp, status=inserted boot:floppy \ No newline at end of file diff --git a/bootloader/bootloader.asm b/bootloader/bootloader.asm index 8e1b6531..af0d5888 100644 --- a/bootloader/bootloader.asm +++ b/bootloader/bootloader.asm @@ -6,7 +6,6 @@ jmp rm_start ; Start in real mode rm_start: - ; Set stack space (4K) and stack segment mov ax, 0x7C0 @@ -63,16 +62,12 @@ rm_start: ; Loading the assembly kernel from floppy - ASM_KERNEL_BASE equ 0x100 ; 0x0100:0x0 = 0x1000 - sectors equ 0x30 ; sectors to read - bootdev equ 0x0 - - mov ax, ASM_KERNEL_BASE + mov ax, 0x90 mov es, ax xor bx, bx mov ah, 0x2 ; Read sectors from memory - mov al, sectors ; Number of sectors to read + mov al, 1 ; Number of sectors to read xor ch, ch ; Cylinder 0 mov cl, 2 ; Sector 2 xor dh, dh ; Head 0 @@ -81,12 +76,12 @@ rm_start: jc read_failed - cmp al, sectors + cmp al, 1 jne read_failed ; Run the assembly kernel - jmp dword ASM_KERNEL_BASE:0x0 + jmp dword 0x90:0x0 reset_failed: mov si, reset_failed_msg @@ -120,4 +115,33 @@ error_end: ; Make a real bootsector times 510-($-$$) db 0 - dw 0xAA55 \ No newline at end of file + dw 0xAA55 + +second_step: + ; Reset disk drive + xor ax, ax + xor ah, ah + mov dl, 0 + int 0x13 + + ; Loading the assembly kernel from floppy + + KERNEL_BASE equ 0x100 ; 0x100:0x0 = 0x1000 + sectors equ 0x40 ; sectors to read + bootdev equ 0x0 + + mov ax, KERNEL_BASE + mov es, ax + xor bx, bx + + mov ah, 0x2 ; Read sectors from memory + mov al, sectors ; Number of sectors to read + xor ch, ch ; Cylinder 0 + mov cl, 3 ; Sector 2 + xor dh, dh ; Head 0 + mov dl, bootdev ; Drive + int 0x13 + + jmp dword KERNEL_BASE:0x0 + + times 1024-($-$$) db 0 \ No newline at end of file diff --git a/fill.bash b/fill.bash index 636b3551..ecc8b574 100644 --- a/fill.bash +++ b/fill.bash @@ -1,5 +1,5 @@ #!/bin/bash size=`stat -c%s kernel/kernel.bin` -let filler_size=8192-$size +let filler_size=16384-$size dd if=/dev/zero of=filler.bin bs=1 count=$filler_size diff --git a/kernel/Makefile b/kernel/Makefile index a25add59..82cff4aa 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,7 +1,7 @@ -KERNEL_FLAGS=-masm=intel -Iinclude/ -O1 -std=c++11 -Wall -Wextra -pedantic -Wold-style-cast -Wshadow -fno-exceptions -fno-rtti -ffreestanding +KERNEL_FLAGS=-masm=intel -Iinclude/ -O1 -std=c++11 -Wall -Wextra -pedantic -Wold-style-cast -Wshadow -fno-exceptions -fno-rtti -ffreestanding -nostartfiles KERNEL_LINK_FLAGS=-std=c++11 -T linker.ld -ffreestanding -O1 -nostdlib -KERNEL_O_FILES=kernel.o keyboard.o console.o kernel_utils.o timer.o shell.o utils.o memory.o thor.o +KERNEL_O_FILES=kernel.o keyboard.o console.o kernel_utils.o timer.o shell.o utils.o memory.o kernel.bin: $(KERNEL_O_FILES) g++ $(KERNEL_LINK_FLAGS) -o kernel.bin.o $(KERNEL_O_FILES) diff --git a/kernel/include/thor.hpp b/kernel/include/thor.hpp index 45bb687f..00b5351a 100644 --- a/kernel/include/thor.hpp +++ b/kernel/include/thor.hpp @@ -8,4 +8,25 @@ void* operator new (size_t size); void operator delete (void *p); +#define ATEXIT_MAX_FUNCS 128 + +extern "C" { + +typedef unsigned uarch_t; + +struct atexit_func_entry_t { + /* + * Each member is at least 4 bytes large. Such that each entry is 12bytes. + * 128 * 12 = 1.5KB exact. + **/ + void (*destructor_func)(void *); + void *obj_ptr; + void *dso_handle; +}; + +int __cxa_atexit(void (*f)(void *), void *objptr, void *dso); +void __cxa_finalize(void *f); + +} + #endif diff --git a/kernel/src/shell.cpp b/kernel/src/shell.cpp index 7497a407..1d20f9a2 100644 --- a/kernel/src/shell.cpp +++ b/kernel/src/shell.cpp @@ -10,6 +10,8 @@ #include "utils.hpp" #include "memory.hpp" +#include + namespace { //Declarations of the different functions @@ -225,6 +227,8 @@ void echo_command(const char* params){ k_print_line(params + 5); } +//std::vector test; + void memory_command(const char*){ if(mmap_failed()){ k_print_line("The mmap was not correctly loaded from e820"); @@ -254,6 +258,10 @@ void memory_command(const char*){ k_printf("Total available memory: %dB\n", available_memory); } } + + std::size_t address; + __asm__ __volatile__ ("mov %0, rsp" : : "a" (address)); + k_printf("%h\n", address); } } //end of anonymous namespace diff --git a/kernel/src/thor.cpp b/kernel/src/thor.cpp index f035e6f8..dc7a4269 100644 --- a/kernel/src/thor.cpp +++ b/kernel/src/thor.cpp @@ -8,3 +8,98 @@ void* operator new (size_t size){ void operator delete (void* p){ k_free(reinterpret_cast(p)); } + +extern "C" { + +atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS]; +uarch_t __atexit_func_count = 0; + +void *__dso_handle = 0; //Attention! Optimally, you should remove the '= 0' part and define this in your asm script. + +int __cxa_atexit(void (*f)(void *), void *objptr, void *dso){ + if (__atexit_func_count >= ATEXIT_MAX_FUNCS) {return -1;}; + __atexit_funcs[__atexit_func_count].destructor_func = f; + __atexit_funcs[__atexit_func_count].obj_ptr = objptr; + __atexit_funcs[__atexit_func_count].dso_handle = dso; + __atexit_func_count++; + return 0; /*I would prefer if functions returned 1 on success, but the ABI says...*/ +} + +void __cxa_finalize(void *f){ + uarch_t i = __atexit_func_count; + if (!f){ + /* + * According to the Itanium C++ ABI, if __cxa_finalize is called without a + * function ptr, then it means that we should destroy EVERYTHING MUAHAHAHA!! + * + * TODO: + * Note well, however, that deleting a function from here that contains a __dso_handle + * means that one link to a shared object file has been terminated. In other words, + * We should monitor this list (optional, of course), since it tells us how many links to + * an object file exist at runtime in a particular application. This can be used to tell + * when a shared object is no longer in use. It is one of many methods, however. + **/ + //You may insert a prinf() here to tell you whether or not the function gets called. Testing + //is CRITICAL! + while (i--) + { + if (__atexit_funcs[i].destructor_func) + { + /* ^^^ That if statement is a safeguard... + * To make sure we don't call any entries that have already been called and unset at runtime. + * Those will contain a value of 0, and calling a function with value 0 + * will cause undefined behaviour. Remember that linear address 0, + * in a non-virtual address space (physical) contains the IVT and BDA. + * + * In a virtual environment, the kernel will receive a page fault, and then probably + * map in some trash, or a blank page, or something stupid like that. + * This will result in the processor executing trash, and...we don't want that. + **/ + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + }; + }; + return; + }; + + for ( ; i >= 0; --i) + { + /* + * The ABI states that multiple calls to the __cxa_finalize(destructor_func_ptr) function + * should not destroy objects multiple times. Only one call is needed to eliminate multiple + * entries with the same address. + * + * FIXME: + * This presents the obvious problem: all destructors must be stored in the order they + * were placed in the list. I.e: the last initialized object's destructor must be first + * in the list of destructors to be called. But removing a destructor from the list at runtime + * creates holes in the table with unfilled entries. + * Remember that the insertion algorithm in __cxa_atexit simply inserts the next destructor + * at the end of the table. So, we have holes with our current algorithm + * This function should be modified to move all the destructors above the one currently + * being called and removed one place down in the list, so as to cover up the hole. + * Otherwise, whenever a destructor is called and removed, an entire space in the table is wasted. + **/ + if (__atexit_funcs[i].destructor_func == f) + { + /* + * Note that in the next line, not every destructor function is a class destructor. + * It is perfectly legal to register a non class destructor function as a simple cleanup + * function to be called on program termination, in which case, it would not NEED an + * object This pointer. A smart programmer may even take advantage of this and register + * a C function in the table with the address of some structure containing data about + * what to clean up on exit. + * In the case of a function that takes no arguments, it will simply be ignore within the + * function itself. No worries. + **/ + (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); + __atexit_funcs[i].destructor_func = 0; + + /* + * Notice that we didn't decrement __atexit_func_count: this is because this algorithm + * requires patching to deal with the FIXME outlined above. + **/ + }; + }; +} + +} diff --git a/micro_kernel/micro_kernel.asm b/micro_kernel/micro_kernel.asm index 62ad160a..46a78494 100644 --- a/micro_kernel/micro_kernel.asm +++ b/micro_kernel/micro_kernel.asm @@ -192,18 +192,18 @@ GDT64: db 0x0 DATA_SELECTOR: ; flat data selector (ring 0) - dw 0x0FFFF - db 0x0, 0x0, 0x0 - db 10010010b - db 10001111b - db 0x0 + dw 0x0FFFF + db 0x0, 0x0, 0x0 + db 10010010b + db 10001111b + db 0x0 LONG_SELECTOR: ; 64-bit code selector (ring 0) - dw 0x0FFFF - db 0x0, 0x0, 0x0 - db 10011010b - db 10101111b - db 0x0 + dw 0x0FFFF + db 0x0, 0x0, 0x0 + db 10011010b + db 10101111b + db 0x0 GDTR64: dw 4 * 8 - 1 ; Length of GDT