Something about heap and memory maps and such. Also fixed C++ global constructors.

This commit is contained in:
Patrick 2024-01-11 17:55:12 +01:00
parent 0348b24f05
commit 97732de3ae
20 changed files with 643 additions and 84 deletions

View File

@ -9,6 +9,7 @@ env['LD'] = 'i686-elf-g++'
env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20']) env.Append(CXXFLAGS = ['-ffreestanding', '-fno-exceptions', '-fno-rtti', '-std=c++20'])
env.Append(LINKFLAGS = ['-T', 'linker.ld', '-ffreestanding', '-nostdlib']) env.Append(LINKFLAGS = ['-T', 'linker.ld', '-ffreestanding', '-nostdlib'])
env.Append(CPPPATH = ['#include']) env.Append(CPPPATH = ['#include'])
env.Append(CCFLAGS = ['-g', '-O0'])
def get_crt_object(name: str) -> str: def get_crt_object(name: str) -> str:
cmd = [env['CXX']] cmd = [env['CXX']]
@ -27,9 +28,12 @@ os_sources = Split('''
src/kernel/boot.s src/kernel/boot.s
src/kernel/startup.cpp src/kernel/startup.cpp
src/os/panic.cpp
src/os/tty.cpp src/os/tty.cpp
src/stdlib/assert.cpp src/stdlib/assert.cpp
src/stdlib/exception.cpp
src/stdlib/new.cpp
src/stdlib/stdio.cpp src/stdlib/stdio.cpp
src/stdlib/stdlib.cpp src/stdlib/stdlib.cpp
src/stdlib/string.cpp src/stdlib/string.cpp

13
include/cstdarg Normal file
View File

@ -0,0 +1,13 @@
#if !defined(BAD_APPLE_OS_CSTDARG_INCLUDED)
#define BAD_APPLE_OS_CSTDARG_INCLUDED
#include <stdarg.h>
namespace std
{
using ::va_list;
}
#endif // !defined(BAD_APPLE_OS_CSTDARG_INCLUDED)

View File

@ -11,6 +11,7 @@ namespace std
using ::putchar; using ::putchar;
using ::puts; using ::puts;
using ::printf; using ::printf;
using ::vprintf;
} }
#endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) #endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED)

View File

@ -9,6 +9,8 @@
namespace std namespace std
{ {
using ::abort; using ::abort;
using ::malloc;
using ::free;
} }
#endif // !defined(BAD_APPLE_OS_CSTDLIB_INCLUDED) #endif // !defined(BAD_APPLE_OS_CSTDLIB_INCLUDED)

50
include/exception Normal file
View File

@ -0,0 +1,50 @@
#if !defined(BAD_APPLE_OS_EXCEPTION_INCLUDED)
#define BAD_APPLE_OS_EXCEPTION_INCLUDED
#include <cstdlib>
#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 = "<unknown>";
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)

19
include/new Normal file
View File

@ -0,0 +1,19 @@
#if !defined(BAD_APPLE_OS_NEW_INCLUDED)
#define BAD_APPLE_OS_NEW_INCLUDED
#include <exception>
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)

10
include/os/panic.hpp Normal file
View File

@ -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)

View File

@ -4,6 +4,7 @@
#if !defined(BAD_APPLE_OS_STDIO_H_INCLUDED) #if !defined(BAD_APPLE_OS_STDIO_H_INCLUDED)
#define BAD_APPLE_OS_STDIO_H_INCLUDED #define BAD_APPLE_OS_STDIO_H_INCLUDED
#include <cstdarg>
#include "./detail/common.h" #include "./detail/common.h"
BA_EXTERN_C_BEGIN BA_EXTERN_C_BEGIN
@ -11,6 +12,7 @@ BA_EXTERN_C_BEGIN
int putchar(int chr) BA_CXX_NOEXCEPT; int putchar(int chr) BA_CXX_NOEXCEPT;
int puts(const char* str) BA_CXX_NOEXCEPT; int puts(const char* str) BA_CXX_NOEXCEPT;
int printf(const char* format, ...) 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 BA_EXTERN_C_END

View File

@ -4,11 +4,14 @@
#if !defined(BAD_APPLE_OS_STDLIB_H_INCLUDED) #if !defined(BAD_APPLE_OS_STDLIB_H_INCLUDED)
#define BAD_APPLE_OS_STDLIB_H_INCLUDED #define BAD_APPLE_OS_STDLIB_H_INCLUDED
#include <stddef.h>
#include "./detail/common.h" #include "./detail/common.h"
BA_EXTERN_C_BEGIN BA_EXTERN_C_BEGIN
BA_CXX_NORETURN void abort(); 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 BA_EXTERN_C_END

View File

@ -31,6 +31,14 @@ SECTIONS
/* Read-only data. */ /* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K) .rodata BLOCK(4K) : ALIGN(4K)
{ {
start_ctors = .;
*(SORT(.ctors*)) /* Note the "SORT" */
end_ctors = .;
start_dtors = .;
*(SORT(.dtors*))
end_dtors = .;
*(.rodata) *(.rodata)
} }

View File

@ -1,17 +1,6 @@
#include <cstdio> #include <cstdio>
#include <cassert>
extern "C" void main() extern "C" void main()
{ {
std::puts("Hello, kernel World!");
while (true)
{
for (char chr = 'A'; chr <= 'Z'; ++chr)
{
std::printf("char: %c", chr);
}
}
} }

View File

@ -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 ALIGN, 1<<0 /* align loaded modules on page boundaries */
.set MEMINFO, 1<<1 /* provide memory map */ .set MEMINFO, 1<<1 /* provide memory map */
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */ .set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */ .set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */ .set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
/* // the actual multiboot header
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.
*/
.section .multiboot .section .multiboot
.align 4 .align 4
.long MAGIC .long MAGIC
.long FLAGS .long FLAGS
.long CHECKSUM .long CHECKSUM
/* // stack section
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.
*/
.section .bss .section .bss
.align 16 .align 16
stack_bottom: stack_bottom:
.skip 16384 # 16 KiB .skip 16384 # 16 KiB
stack_top: stack_top:
/* // kernel entry point
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.
*/
.section .text .section .text
.global _start .global _start
.type _start, @function .type _start, @function
@ -58,49 +37,40 @@ _start:
machine. machine.
*/ */
/* // store the multiboot info
To set up a stack, we set the esp register to point to the top of the mov %ebx, (gMultibootHeader)
stack (as it grows downwards on x86 systems). This is necessarily done
in assembly as languages such as C cannot function without a stack. // setup stack
*/
mov $stack_top, %esp mov $stack_top, %esp
/* // call the constructors
This is a good place to initialize crucial processor state before the mov $start_ctors, %ebx
high-level kernel is entered. It's best to minimize the early jmp .ctors_loop_end
environment where crucial features are offline. Note that the .ctors_loop_start:
processor is not fully initialized yet: Features such as floating call *(%ebx)
point instructions and instruction set extensions are not initialized add 4, %ebx
yet. The GDT should be loaded here. Paging should be enabled here. .ctors_loop_end:
C++ features such as global constructors and exceptions will require cmp $end_ctors, %ebx
runtime support to work as well. jb .ctors_loop_start
*/
/* // enter high-level kernel
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.
*/
call kernel_main call kernel_main
/* // // call the destructors
If the system has nothing more to do, put the computer into an // mov $start_dtors, %ebx
infinite loop. To do that: // jmp .dtors_loop_end
1) Disable interrupts with cli (clear interrupt enable in eflags). //.dtors_loop_start:
They are already disabled by the bootloader, so this is not needed. // call *(%ebx)
Mind that you might later enable interrupts and return from // add 4, %ebx
kernel_main (which is sort of nonsensical to do). //.dtors_loop_end:
2) Wait for the next interrupt to arrive with hlt (halt instruction). // cmp $end_dtors, %ebx
Since they are disabled, this will lock up the computer. // jb .dtors_loop_start
3) Jump to the hlt instruction if it ever wakes up due to a
non-maskable interrupt occurring or due to system management mode. // We are done. Clear interrupts and halt.
*/
cli cli
1: hlt .kernel_end:
jmp 1b hlt
jmp .kernel_end
/* /*
Set the size of the _start symbol to the current location '.' minus its start. Set the size of the _start symbol to the current location '.' minus its start.

274
src/kernel/multiboot.h Normal file
View File

@ -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 */

View File

@ -1,12 +1,50 @@
#include "os/tty.hpp" #include "os/tty.hpp"
extern "C" void main(); #include <cassert>
#include <cstdio>
#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<multiboot_memory_map_t*>(addr);
if(entry.type == MULTIBOOT_MEMORY_AVAILABLE)
{
std::printf("Start Addr: %d | Length: %d | Size: %d | Type: %d\n",
static_cast<int>(entry.addr), static_cast<int>(entry.len),
static_cast<int>(entry.size), static_cast<int>(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 */ /* Initialize terminal interface */
tty::initialize(); tty::initialize();
/* Initialize the heap */
assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);
initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length);
main(); main();
_fini();
} }
} // extern "C"

26
src/os/panic.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "os/panic.hpp"
#include <stdarg.h>
#include <cstdio>
#include <cstdlib>
#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();
}

View File

@ -13,7 +13,7 @@ void __ba__assert_fail(const char* filename, int line, const char* condition) no
Assertion failed: Assertion failed:
File: %s File: %s
Line: %d Line: %d
Condition: %s)", filename, line, condition); Condition: %s)" "\n", filename, line, condition);
std::abort(); std::abort();
} }
#endif #endif

17
src/stdlib/exception.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <exception>
namespace std
{
const char* exception::what() const noexcept
{
return "";
}
}
#if !defined(__cpp_exceptions)
namespace ba::impl
{
ExceptionAbortHelper gAbortHelper;
}
#endif

50
src/stdlib/new.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <new>
#include <cstdlib>
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);
}

View File

@ -57,7 +57,13 @@ int printf(const char* format, ...) noexcept
{ {
va_list parameters; va_list parameters;
va_start(parameters, format); 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; int result = 0;
const char* pos = format; const char* pos = format;
while (*pos != '\0') while (*pos != '\0')
@ -74,18 +80,17 @@ int printf(const char* format, ...) noexcept
case '\0': case '\0':
// TODO: invalid format string, do something // TODO: invalid format string, do something
assert(!"Invalid format string, ends with %."); assert(!"Invalid format string, ends with %.");
va_end(parameters);
return -1; return -1;
case 'c': case 'c':
{ {
const char chr = static_cast<char>(va_arg(parameters, int)); const char chr = static_cast<char>(va_arg(vlist, int));
putchar(chr); putchar(chr);
++result; ++result;
break; break;
} }
case 's': 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); const size_t len = std::strlen(str);
for (size_t idx = 0; idx < len; ++idx) for (size_t idx = 0; idx < len; ++idx)
@ -96,11 +101,10 @@ int printf(const char* format, ...) noexcept
break; break;
} }
case 'd': case 'd':
result += printInt(va_arg(parameters, int)); result += printInt(va_arg(vlist, int));
break; break;
default: default:
assert(!"Invalid format string, unknown format identifier."); assert(!"Invalid format string, unknown format identifier.");
va_end(parameters);
return -1; return -1;
} }
} else } else
@ -109,8 +113,6 @@ int printf(const char* format, ...) noexcept
} }
++pos; ++pos;
} }
va_end(parameters);
putchar('\n');
++result; ++result;
return result; return result;
} }

View File

@ -1,12 +1,93 @@
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h>
#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<MallocBlock*>(gInitMallocSpace);
initialBlock->elements = INIT_MALLOC_SPACE_ELEMENTS;
initialBlock->nextBlock = nullptr;
return initialBlock;
}();
}
extern "C" extern "C"
{ {
void abort() void abort()
{ {
tty::write("Abort called!");
__asm__ volatile("hlt"); __asm__ volatile("hlt");
while(true) {}; while(true) {};
__builtin_unreachable(); __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<MallocBlock*>(reinterpret_cast<max_align_t*>(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<AllocInfo*>(block);
allocInfo->elements = requiredElements;
return reinterpret_cast<max_align_t*>(block) + 1;
}
prevBlock = block;
}
return nullptr;
}
void free(void* memory) noexcept
{
if (memory == nullptr)
{
return;
}
MallocBlock* block = reinterpret_cast<MallocBlock*>(static_cast<max_align_t*>(memory) - 1);
block->nextBlock = gNextBlock;
gNextBlock = block;
}
} // extern "C"