From 97732de3ae7db6f29676f5208bf25416b8fb1699 Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Thu, 11 Jan 2024 17:55:12 +0100 Subject: [PATCH] Something about heap and memory maps and such. Also fixed C++ global constructors. --- SConstruct | 4 + include/cstdarg | 13 ++ include/cstdio | 1 + include/cstdlib | 2 + include/exception | 50 +++++++ include/new | 19 +++ include/os/panic.hpp | 10 ++ include/stdio.h | 2 + include/stdlib.h | 3 + linker.ld | 8 ++ src/app/main.cpp | 11 -- src/kernel/boot.s | 94 +++++--------- src/kernel/multiboot.h | 274 +++++++++++++++++++++++++++++++++++++++ src/kernel/startup.cpp | 42 +++++- src/os/panic.cpp | 26 ++++ src/stdlib/assert.cpp | 2 +- src/stdlib/exception.cpp | 17 +++ src/stdlib/new.cpp | 50 +++++++ src/stdlib/stdio.cpp | 16 ++- src/stdlib/stdlib.cpp | 83 +++++++++++- 20 files changed, 643 insertions(+), 84 deletions(-) create mode 100644 include/cstdarg create mode 100644 include/exception create mode 100644 include/new create mode 100644 include/os/panic.hpp create mode 100644 src/kernel/multiboot.h create mode 100644 src/os/panic.cpp create mode 100644 src/stdlib/exception.cpp create mode 100644 src/stdlib/new.cpp diff --git a/SConstruct b/SConstruct index c3a7198..f0818d0 100644 --- a/SConstruct +++ b/SConstruct @@ -9,6 +9,7 @@ env['LD'] = 'i686-elf-g++' env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20']) env.Append(LINKFLAGS = ['-T', 'linker.ld', '-ffreestanding', '-nostdlib']) env.Append(CPPPATH = ['#include']) +env.Append(CCFLAGS = ['-g', '-O0']) def get_crt_object(name: str) -> str: cmd = [env['CXX']] @@ -27,9 +28,12 @@ os_sources = Split(''' src/kernel/boot.s src/kernel/startup.cpp + src/os/panic.cpp src/os/tty.cpp src/stdlib/assert.cpp + src/stdlib/exception.cpp + src/stdlib/new.cpp src/stdlib/stdio.cpp src/stdlib/stdlib.cpp src/stdlib/string.cpp diff --git a/include/cstdarg b/include/cstdarg new file mode 100644 index 0000000..4278827 --- /dev/null +++ b/include/cstdarg @@ -0,0 +1,13 @@ + + +#if !defined(BAD_APPLE_OS_CSTDARG_INCLUDED) +#define BAD_APPLE_OS_CSTDARG_INCLUDED + +#include + +namespace std +{ +using ::va_list; +} + +#endif // !defined(BAD_APPLE_OS_CSTDARG_INCLUDED) diff --git a/include/cstdio b/include/cstdio index 985a515..639fc10 100644 --- a/include/cstdio +++ b/include/cstdio @@ -11,6 +11,7 @@ namespace std using ::putchar; using ::puts; using ::printf; +using ::vprintf; } #endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) diff --git a/include/cstdlib b/include/cstdlib index 7daf01e..d53df3f 100644 --- a/include/cstdlib +++ b/include/cstdlib @@ -9,6 +9,8 @@ namespace std { using ::abort; +using ::malloc; +using ::free; } #endif // !defined(BAD_APPLE_OS_CSTDLIB_INCLUDED) diff --git a/include/exception b/include/exception new file mode 100644 index 0000000..8b6e566 --- /dev/null +++ b/include/exception @@ -0,0 +1,50 @@ + +#if !defined(BAD_APPLE_OS_EXCEPTION_INCLUDED) +#define BAD_APPLE_OS_EXCEPTION_INCLUDED + +#include +#include "os/panic.hpp" + +#if defined(__cpp_exceptions) +#define __ba_throw throw +#else +#define __ba_throw ba::impl::gAbortHelper(__FILE__, __LINE__) = +#endif + +namespace std +{ +class exception +{ +public: + virtual ~exception() noexcept = default; + virtual const char* what() const noexcept; +}; +} + +#if !defined(__cpp_exceptions) +namespace ba::impl +{ +struct ExceptionAbortHelper +{ +private: + const char* mFile = ""; + int mLine = -1; +public: + [[noreturn]] ExceptionAbortHelper& operator=(const std::exception& ex) noexcept + { + panicf("Uncaught exception with message \"%s\" at %s:%d.", ex.what(), mFile, mLine); + } + + ExceptionAbortHelper& operator()(const char* file, int line) noexcept + { + mFile = file; + mLine = line; + return *this; + } +}; + +extern ExceptionAbortHelper gAbortHelper; +} +#endif // !defined(__cpp_exceptions) + +#endif // !defined(BAD_APPLE_OS_EXCEPTION_INCLUDED) diff --git a/include/new b/include/new new file mode 100644 index 0000000..7571f8b --- /dev/null +++ b/include/new @@ -0,0 +1,19 @@ + +#if !defined(BAD_APPLE_OS_NEW_INCLUDED) +#define BAD_APPLE_OS_NEW_INCLUDED + +#include + +namespace std +{ +class bad_alloc : public std::exception +{ +public: + bad_alloc() noexcept = default; + bad_alloc(const bad_alloc&) noexcept = default; + + const char * what() const noexcept override; +}; +} + +#endif // !defined(BAD_APPLE_OS_NEW_INCLUDED) diff --git a/include/os/panic.hpp b/include/os/panic.hpp new file mode 100644 index 0000000..39e9c83 --- /dev/null +++ b/include/os/panic.hpp @@ -0,0 +1,10 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_PANIC_HPP_INCLUDED) +#define BAD_APPLE_OS_PANIC_HPP_INCLUDED + +[[noreturn]] void panic(const char* message) noexcept; +[[noreturn]] void panicf(const char* format, ...) noexcept; + +#endif // !defined(BAD_APPLE_OS_PANIC_HPP_INCLUDED) diff --git a/include/stdio.h b/include/stdio.h index 01fa7ca..6fbde14 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -4,6 +4,7 @@ #if !defined(BAD_APPLE_OS_STDIO_H_INCLUDED) #define BAD_APPLE_OS_STDIO_H_INCLUDED +#include #include "./detail/common.h" BA_EXTERN_C_BEGIN @@ -11,6 +12,7 @@ BA_EXTERN_C_BEGIN int putchar(int chr) BA_CXX_NOEXCEPT; int puts(const char* str) BA_CXX_NOEXCEPT; int printf(const char* format, ...) BA_CXX_NOEXCEPT; +int vprintf(const char* format, std::va_list vlist) BA_CXX_NOEXCEPT; BA_EXTERN_C_END diff --git a/include/stdlib.h b/include/stdlib.h index a676de9..ba0418a 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -4,11 +4,14 @@ #if !defined(BAD_APPLE_OS_STDLIB_H_INCLUDED) #define BAD_APPLE_OS_STDLIB_H_INCLUDED +#include #include "./detail/common.h" BA_EXTERN_C_BEGIN BA_CXX_NORETURN void abort(); +BA_CXX_NODISCARD void* malloc(size_t size) BA_CXX_NOEXCEPT; +void free(void* ptr) BA_CXX_NOEXCEPT; BA_EXTERN_C_END diff --git a/linker.ld b/linker.ld index 269cda1..cc52870 100644 --- a/linker.ld +++ b/linker.ld @@ -31,6 +31,14 @@ SECTIONS /* Read-only data. */ .rodata BLOCK(4K) : ALIGN(4K) { + start_ctors = .; + *(SORT(.ctors*)) /* Note the "SORT" */ + end_ctors = .; + + start_dtors = .; + *(SORT(.dtors*)) + end_dtors = .; + *(.rodata) } diff --git a/src/app/main.cpp b/src/app/main.cpp index 72c9070..763fc35 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1,17 +1,6 @@ #include -#include - extern "C" void main() { - std::puts("Hello, kernel World!"); - - while (true) - { - for (char chr = 'A'; chr <= 'Z'; ++chr) - { - std::printf("char: %c", chr); - } - } } diff --git a/src/kernel/boot.s b/src/kernel/boot.s index 66c98bc..f502c78 100644 --- a/src/kernel/boot.s +++ b/src/kernel/boot.s @@ -1,46 +1,25 @@ -/* Declare constants for the multiboot header. */ +// constants for the multiboot header .set ALIGN, 1<<0 /* align loaded modules on page boundaries */ .set MEMINFO, 1<<1 /* provide memory map */ .set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */ .set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */ .set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */ -/* -Declare a multiboot header that marks the program as a kernel. These are magic -values that are documented in the multiboot standard. The bootloader will -search for this signature in the first 8 KiB of the kernel file, aligned at a -32-bit boundary. The signature is in its own section so the header can be -forced to be within the first 8 KiB of the kernel file. -*/ +// the actual multiboot header .section .multiboot .align 4 .long MAGIC .long FLAGS .long CHECKSUM -/* -The multiboot standard does not define the value of the stack pointer register -(esp) and it is up to the kernel to provide a stack. This allocates room for a -small stack by creating a symbol at the bottom of it, then allocating 16384 -bytes for it, and finally creating a symbol at the top. The stack grows -downwards on x86. The stack is in its own section so it can be marked nobits, -which means the kernel file is smaller because it does not contain an -uninitialized stack. The stack on x86 must be 16-byte aligned according to the -System V ABI standard and de-facto extensions. The compiler will assume the -stack is properly aligned and failure to align the stack will result in -undefined behavior. -*/ +// stack section .section .bss .align 16 stack_bottom: .skip 16384 # 16 KiB stack_top: -/* -The linker script specifies _start as the entry point to the kernel and the -bootloader will jump to this position once the kernel has been loaded. It -doesn't make sense to return from this function as the bootloader is gone. -*/ +// kernel entry point .section .text .global _start .type _start, @function @@ -58,49 +37,40 @@ _start: machine. */ - /* - To set up a stack, we set the esp register to point to the top of the - stack (as it grows downwards on x86 systems). This is necessarily done - in assembly as languages such as C cannot function without a stack. - */ + // store the multiboot info + mov %ebx, (gMultibootHeader) + + // setup stack mov $stack_top, %esp - /* - This is a good place to initialize crucial processor state before the - high-level kernel is entered. It's best to minimize the early - environment where crucial features are offline. Note that the - processor is not fully initialized yet: Features such as floating - point instructions and instruction set extensions are not initialized - yet. The GDT should be loaded here. Paging should be enabled here. - C++ features such as global constructors and exceptions will require - runtime support to work as well. - */ + // call the constructors + mov $start_ctors, %ebx + jmp .ctors_loop_end +.ctors_loop_start: + call *(%ebx) + add 4, %ebx +.ctors_loop_end: + cmp $end_ctors, %ebx + jb .ctors_loop_start - /* - Enter the high-level kernel. The ABI requires the stack is 16-byte - aligned at the time of the call instruction (which afterwards pushes - the return pointer of size 4 bytes). The stack was originally 16-byte - aligned above and we've pushed a multiple of 16 bytes to the - stack since (pushed 0 bytes so far), so the alignment has thus been - preserved and the call is well defined. - */ + // enter high-level kernel call kernel_main - /* - If the system has nothing more to do, put the computer into an - infinite loop. To do that: - 1) Disable interrupts with cli (clear interrupt enable in eflags). - They are already disabled by the bootloader, so this is not needed. - Mind that you might later enable interrupts and return from - kernel_main (which is sort of nonsensical to do). - 2) Wait for the next interrupt to arrive with hlt (halt instruction). - Since they are disabled, this will lock up the computer. - 3) Jump to the hlt instruction if it ever wakes up due to a - non-maskable interrupt occurring or due to system management mode. - */ +// // call the destructors +// mov $start_dtors, %ebx +// jmp .dtors_loop_end +//.dtors_loop_start: +// call *(%ebx) +// add 4, %ebx +//.dtors_loop_end: +// cmp $end_dtors, %ebx +// jb .dtors_loop_start + + // We are done. Clear interrupts and halt. cli -1: hlt - jmp 1b +.kernel_end: + hlt + jmp .kernel_end /* Set the size of the _start symbol to the current location '.' minus its start. diff --git a/src/kernel/multiboot.h b/src/kernel/multiboot.h new file mode 100644 index 0000000..f6302ea --- /dev/null +++ b/src/kernel/multiboot.h @@ -0,0 +1,274 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the ’flags’ member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info +{ + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ diff --git a/src/kernel/startup.cpp b/src/kernel/startup.cpp index 8cd5b64..9ddcb80 100644 --- a/src/kernel/startup.cpp +++ b/src/kernel/startup.cpp @@ -1,12 +1,50 @@ #include "os/tty.hpp" -extern "C" void main(); +#include +#include +#include "./multiboot.h" -extern "C" void kernel_main(void) +namespace { +void initHeapFromMultibootHeader(const uint32_t firstEntryAddr, const size_t bufferLength) noexcept +{ + for (uint32_t addr = firstEntryAddr; addr < firstEntryAddr + bufferLength;) + { + const multiboot_memory_map_t& entry = *reinterpret_cast(addr); + + if(entry.type == MULTIBOOT_MEMORY_AVAILABLE) + { + std::printf("Start Addr: %d | Length: %d | Size: %d | Type: %d\n", + static_cast(entry.addr), static_cast(entry.len), + static_cast(entry.size), static_cast(entry.type)); + } + addr += sizeof(entry.size) + entry.size; + } +} +} + +extern "C" +{ +multiboot_info_t* gMultibootHeader; + +void _init(); +void _fini(); +void main(); + +void kernel_main() +{ + _init(); + /* Initialize terminal interface */ tty::initialize(); + /* Initialize the heap */ + assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP); + initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length); + main(); + + _fini(); } +} // extern "C" diff --git a/src/os/panic.cpp b/src/os/panic.cpp new file mode 100644 index 0000000..849fa1f --- /dev/null +++ b/src/os/panic.cpp @@ -0,0 +1,26 @@ + +#include "os/panic.hpp" + +#include +#include +#include +#include "os/tty.hpp" + +void panic(const char* message) noexcept +{ + tty::write("Kernel panic!\n"); + tty::write(message); + tty::putChar('\n'); + std::abort(); +} + +void panicf(const char* format, ...) noexcept +{ + tty::write("Kernel panic!\n"); + va_list parameters; + va_start(parameters, format); + std::vprintf(format, parameters); + va_end(parameters); + tty::putChar('\n'); + std::abort(); +} diff --git a/src/stdlib/assert.cpp b/src/stdlib/assert.cpp index 9f85db4..b973711 100644 --- a/src/stdlib/assert.cpp +++ b/src/stdlib/assert.cpp @@ -13,7 +13,7 @@ void __ba__assert_fail(const char* filename, int line, const char* condition) no Assertion failed: File: %s Line: %d -Condition: %s)", filename, line, condition); +Condition: %s)" "\n", filename, line, condition); std::abort(); } #endif diff --git a/src/stdlib/exception.cpp b/src/stdlib/exception.cpp new file mode 100644 index 0000000..b392a4c --- /dev/null +++ b/src/stdlib/exception.cpp @@ -0,0 +1,17 @@ + +#include + +namespace std +{ +const char* exception::what() const noexcept +{ + return ""; +} +} + +#if !defined(__cpp_exceptions) +namespace ba::impl +{ +ExceptionAbortHelper gAbortHelper; +} +#endif diff --git a/src/stdlib/new.cpp b/src/stdlib/new.cpp new file mode 100644 index 0000000..e0afb01 --- /dev/null +++ b/src/stdlib/new.cpp @@ -0,0 +1,50 @@ + +#include + +#include + +namespace std +{ +const char* bad_alloc::what() const noexcept +{ + return "bad_alloc"; +} +} + +void* operator new(size_t count) +{ + if (void* ptr = malloc(count); ptr != nullptr) + { + return ptr; + } + __ba_throw std::bad_alloc(); +} + +void operator delete(void* data) noexcept +{ + std::free(data); +} + +void* operator new[](size_t count) +{ + if (void* ptr = malloc(count); ptr != nullptr) + { + return ptr; + } + __ba_throw std::bad_alloc(); +} + +void operator delete[](void* data) noexcept +{ + std::free(data); +} + +void operator delete(void* data, size_t /* size */) noexcept +{ + std::free(data); +} + +void operator delete[](void* data, size_t /* size */) noexcept +{ + std::free(data); +} diff --git a/src/stdlib/stdio.cpp b/src/stdlib/stdio.cpp index b37613b..046d6fc 100644 --- a/src/stdlib/stdio.cpp +++ b/src/stdlib/stdio.cpp @@ -57,7 +57,13 @@ int printf(const char* format, ...) noexcept { va_list parameters; va_start(parameters, format); + const int result = vprintf(format, parameters); + va_end(parameters); + return result; +} +int vprintf(const char* format, std::va_list vlist) BA_CXX_NOEXCEPT +{ int result = 0; const char* pos = format; while (*pos != '\0') @@ -74,18 +80,17 @@ int printf(const char* format, ...) noexcept case '\0': // TODO: invalid format string, do something assert(!"Invalid format string, ends with %."); - va_end(parameters); return -1; case 'c': { - const char chr = static_cast(va_arg(parameters, int)); + const char chr = static_cast(va_arg(vlist, int)); putchar(chr); ++result; break; } case 's': { - const char* str = va_arg(parameters, const char*); + const char* str = va_arg(vlist, const char*); const size_t len = std::strlen(str); for (size_t idx = 0; idx < len; ++idx) @@ -96,11 +101,10 @@ int printf(const char* format, ...) noexcept break; } case 'd': - result += printInt(va_arg(parameters, int)); + result += printInt(va_arg(vlist, int)); break; default: assert(!"Invalid format string, unknown format identifier."); - va_end(parameters); return -1; } } else @@ -109,8 +113,6 @@ int printf(const char* format, ...) noexcept } ++pos; } - va_end(parameters); - putchar('\n'); ++result; return result; } diff --git a/src/stdlib/stdlib.cpp b/src/stdlib/stdlib.cpp index 160085c..3be7c37 100644 --- a/src/stdlib/stdlib.cpp +++ b/src/stdlib/stdlib.cpp @@ -1,12 +1,93 @@ #include +#include +#include "os/tty.hpp" + +namespace +{ +inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024; +inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t); + +max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS]; + +struct MallocBlock +{ + size_t elements; + MallocBlock* nextBlock; +}; +struct AllocInfo +{ + size_t elements; +}; +static_assert(sizeof(MallocBlock) <= sizeof(max_align_t)); +static_assert(sizeof(AllocInfo) <= sizeof(max_align_t)); + +MallocBlock* gNextBlock = []() +{ + MallocBlock* initialBlock = reinterpret_cast(gInitMallocSpace); + initialBlock->elements = INIT_MALLOC_SPACE_ELEMENTS; + initialBlock->nextBlock = nullptr; + return initialBlock; +}(); +} + extern "C" { void abort() { + tty::write("Abort called!"); __asm__ volatile("hlt"); while(true) {}; __builtin_unreachable(); } -} // extern "C" + +void* malloc(size_t size) noexcept +{ + if (size == 0) + { + return nullptr; + } + + const size_t requiredElements = (size + sizeof(max_align_t) - 1) / sizeof(max_align_t) + 1; + MallocBlock* prevBlock = nullptr; + for (MallocBlock* block = gNextBlock; block != nullptr; block = block->nextBlock) + { + if (block->elements >= requiredElements) + { + MallocBlock* newBlock = nullptr; + if (block->elements > requiredElements) + { + newBlock = reinterpret_cast(reinterpret_cast(block) + requiredElements); + newBlock->nextBlock = block->nextBlock; + newBlock->elements = block->elements - requiredElements; + } + else + { + newBlock = block->nextBlock; + } + if (prevBlock != nullptr) + { + prevBlock->nextBlock = newBlock; + } + AllocInfo* allocInfo = reinterpret_cast(block); + allocInfo->elements = requiredElements; + return reinterpret_cast(block) + 1; + } + prevBlock = block; + } + + return nullptr; +} + +void free(void* memory) noexcept +{ + if (memory == nullptr) + { + return; + } + MallocBlock* block = reinterpret_cast(static_cast(memory) - 1); + block->nextBlock = gNextBlock; + gNextBlock = block; +} +} // extern "C" \ No newline at end of file