This is the first of two rather big changes to clean up includes throughout the project. In this commit, the implicit semi-dependency on libc that bonnibel adds to every module is removed. Previously, I was sloppy with includes of libc headers and include directory order. Now, the freestanding headers from libc are split out into libc_free, and an implicit real dependency is added onto this module, unless `no_libc` is set to `True`. The full libc needs to be explicitly specified as a dependency to be used. Several things needed to change in order to do this: - Many places use `memset` or `memcpy` that cannot depend on libc. The kernel has basic implementations of them itself for this reason. Now those functions are moved into the lower-level `j6/memutils.h`, and libc merely references them. Other modules are now free to reference those functions from libj6 instead. - The kernel's `assert.h` was renamed kassert.h (matching its `kassert` function) so that the new `util/assert.h` can use `__has_include` to detect it and make sure the `assert` macro is usable in libutil code. - Several implementation header files under `__libj6/` also moved under the new libc_free. - A new `include_phase` property has been added to modules for Bonnibel, which can be "normal" (default) or "late" which uses `-idirafter` instead of `-I` for includes. - Since `<utility>` and `<new>` are not freestanding, implementations of `remove_reference`, `forward`, `move`, and `swap` were added to the `util` namespace to replace those from `std`, and `util/new.h` was added to declare `operator new` and `operator delete`.
75 lines
1.9 KiB
C++
75 lines
1.9 KiB
C++
#include <util/new.h>
|
|
#include <util/no_construct.h>
|
|
|
|
#include "cpu.h"
|
|
#include "display.h"
|
|
#include "io.h"
|
|
#include "serial.h"
|
|
#include "symbol_table.h"
|
|
|
|
struct cpu_state;
|
|
|
|
bool main_cpu_done = false;
|
|
bool asserting_locked = false;
|
|
unsigned remaining = 0;
|
|
|
|
util::no_construct<panicking::serial_port> __com1_storage;
|
|
panicking::serial_port &com1 = __com1_storage.value;
|
|
|
|
util::no_construct<panicking::symbol_table> __syms_storage;
|
|
panicking::symbol_table &syms = __syms_storage.value;
|
|
|
|
static constexpr int order = __ATOMIC_ACQ_REL;
|
|
|
|
extern "C"
|
|
void panic_handler(const cpu_state *regs)
|
|
{
|
|
cpu_data &cpu = current_cpu();
|
|
panic_data *panic = cpu.panic;
|
|
|
|
// If we're not running on the CPU that panicked, wait
|
|
// for it to finish
|
|
if (!panic) {
|
|
while (!main_cpu_done);
|
|
} else {
|
|
new (&com1) panicking::serial_port {panicking::COM1};
|
|
new (&syms) panicking::symbol_table {panic->symbol_data};
|
|
remaining = panic->cpus;
|
|
}
|
|
|
|
while (__atomic_test_and_set(&asserting_locked, order))
|
|
asm ("pause");
|
|
|
|
panicking::frame const *fp = nullptr;
|
|
asm ( "movq (%%rbp), %0" : "=r" (fp) );
|
|
|
|
if (panic)
|
|
print_header(com1, panic->message, panic->function,
|
|
panic->file, panic->line);
|
|
|
|
print_cpu(com1, cpu);
|
|
print_callstack(com1, syms, fp);
|
|
print_cpu_state(com1, *regs);
|
|
|
|
if (panic && panic->user_state)
|
|
print_user_state(com1, *panic->user_state);
|
|
|
|
__atomic_clear(&asserting_locked, order);
|
|
|
|
// If we're running on the CPU that panicked, tell the
|
|
// others we have finished
|
|
main_cpu_done = true;
|
|
|
|
if (__atomic_sub_fetch(&remaining, 1, order) == 0) {
|
|
// No remaining CPUs, if we're running on QEMU,
|
|
// tell it to exit
|
|
constexpr uint32_t exit_code = 255;
|
|
asm ( "outl %%eax, %%dx" :: "a"(exit_code), "d"(0xf4) );
|
|
}
|
|
|
|
while (1) asm ("hlt");
|
|
}
|
|
|
|
#define NDEBUG
|
|
#include "../cpprt.cpp"
|