mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-13 14:36:37 -04:00
Prepare support for global destructors
This commit is contained in:
parent
cc9930c6c8
commit
87ca442f12
9
Makefile
9
Makefile
@ -23,7 +23,14 @@ qemu: thor.flp
|
|||||||
qemu-kvm -cpu host -fda thor.flp
|
qemu-kvm -cpu host -fda thor.flp
|
||||||
|
|
||||||
bochs: 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:
|
force_look:
|
||||||
true
|
true
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
|
display_library: sdl
|
||||||
|
magic_break: enabled=1
|
||||||
floppya: 1_44=thor.flp, status=inserted
|
floppya: 1_44=thor.flp, status=inserted
|
||||||
boot:floppy
|
boot:floppy
|
@ -6,7 +6,6 @@ jmp rm_start
|
|||||||
|
|
||||||
; Start in real mode
|
; Start in real mode
|
||||||
rm_start:
|
rm_start:
|
||||||
|
|
||||||
; Set stack space (4K) and stack segment
|
; Set stack space (4K) and stack segment
|
||||||
|
|
||||||
mov ax, 0x7C0
|
mov ax, 0x7C0
|
||||||
@ -63,16 +62,12 @@ rm_start:
|
|||||||
|
|
||||||
; Loading the assembly kernel from floppy
|
; Loading the assembly kernel from floppy
|
||||||
|
|
||||||
ASM_KERNEL_BASE equ 0x100 ; 0x0100:0x0 = 0x1000
|
mov ax, 0x90
|
||||||
sectors equ 0x30 ; sectors to read
|
|
||||||
bootdev equ 0x0
|
|
||||||
|
|
||||||
mov ax, ASM_KERNEL_BASE
|
|
||||||
mov es, ax
|
mov es, ax
|
||||||
xor bx, bx
|
xor bx, bx
|
||||||
|
|
||||||
mov ah, 0x2 ; Read sectors from memory
|
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
|
xor ch, ch ; Cylinder 0
|
||||||
mov cl, 2 ; Sector 2
|
mov cl, 2 ; Sector 2
|
||||||
xor dh, dh ; Head 0
|
xor dh, dh ; Head 0
|
||||||
@ -81,12 +76,12 @@ rm_start:
|
|||||||
|
|
||||||
jc read_failed
|
jc read_failed
|
||||||
|
|
||||||
cmp al, sectors
|
cmp al, 1
|
||||||
jne read_failed
|
jne read_failed
|
||||||
|
|
||||||
; Run the assembly kernel
|
; Run the assembly kernel
|
||||||
|
|
||||||
jmp dword ASM_KERNEL_BASE:0x0
|
jmp dword 0x90:0x0
|
||||||
|
|
||||||
reset_failed:
|
reset_failed:
|
||||||
mov si, reset_failed_msg
|
mov si, reset_failed_msg
|
||||||
@ -121,3 +116,32 @@ error_end:
|
|||||||
|
|
||||||
times 510-($-$$) db 0
|
times 510-($-$$) db 0
|
||||||
dw 0xAA55
|
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
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
size=`stat -c%s kernel/kernel.bin`
|
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
|
dd if=/dev/zero of=filler.bin bs=1 count=$filler_size
|
||||||
|
@ -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_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)
|
kernel.bin: $(KERNEL_O_FILES)
|
||||||
g++ $(KERNEL_LINK_FLAGS) -o kernel.bin.o $(KERNEL_O_FILES)
|
g++ $(KERNEL_LINK_FLAGS) -o kernel.bin.o $(KERNEL_O_FILES)
|
||||||
|
@ -8,4 +8,25 @@
|
|||||||
void* operator new (size_t size);
|
void* operator new (size_t size);
|
||||||
void operator delete (void *p);
|
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
|
#endif
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
//Declarations of the different functions
|
//Declarations of the different functions
|
||||||
@ -225,6 +227,8 @@ void echo_command(const char* params){
|
|||||||
k_print_line(params + 5);
|
k_print_line(params + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//std::vector<std::size_t> test;
|
||||||
|
|
||||||
void memory_command(const char*){
|
void memory_command(const char*){
|
||||||
if(mmap_failed()){
|
if(mmap_failed()){
|
||||||
k_print_line("The mmap was not correctly loaded from e820");
|
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);
|
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
|
} //end of anonymous namespace
|
||||||
|
@ -8,3 +8,98 @@ void* operator new (size_t size){
|
|||||||
void operator delete (void* p){
|
void operator delete (void* p){
|
||||||
k_free(reinterpret_cast<std::size_t*>(p));
|
k_free(reinterpret_cast<std::size_t*>(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.
|
||||||
|
**/
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user