Files
jsix_import/src/boot/main.cpp
Justin C. Miller eeef23c2b7 [panic] Have panics stop all cores
Kernel panics previously only stopped the calling core. This commit
re-implements the panic system to allow us to stop all cores on a panic.

Changes include:

- panic now sends an NMI to all cores. This means we can't control the
  contents of their registers, so panic information has been moved to a
  global struct, and the panicking cpu sets the pointer to that data in
  its cpu_data.
- the panic_handler is now set up with mutexes to print appropriately
  and only initialize objects once.
- copying _current_gsbase into the panic handler, and #including the
  cpprt.cpp file (so that we can define NDEBUG and not have it try to
  link the assert code back in)
- making the symbol data pointer in kargs an actual pointer again, not
  an address - and carrying that through to the panic handler
- the number of cpus is now saved globally in the kernel as g_num_cpus
2022-01-08 01:00:43 -08:00

199 lines
5.4 KiB
C++

#include <uefi/types.h>
#include <uefi/guid.h>
#include <uefi/tables.h>
#include <uefi/protos/simple_text_output.h>
#include <stdalign.h>
#include <stddef.h>
#include <stdint.h>
#include <bootproto/bootconfig.h>
#include <bootproto/kernel.h>
#include <bootproto/memory.h>
#include <util/counted.h>
#include <util/pointers.h>
#include "allocator.h"
#include "bootconfig.h"
#include "console.h"
#include "error.h"
#include "fs.h"
#include "hardware.h"
#include "loader.h"
#include "memory.h"
#include "memory_map.h"
#include "paging.h"
#include "status.h"
#include "video.h"
namespace boot {
/// Change a pointer to point to the higher-half linear-offset version
/// of the address it points to.
template <typename T>
void change_pointer(T *&pointer)
{
pointer = util::offset_pointer(pointer, bootproto::mem::linear_offset);
}
/// The main procedure for the portion of the loader that runs while
/// UEFI is still in control of the machine. (ie, while the loader still
/// has access to boot services.)
bootproto::args *
uefi_preboot(uefi::handle image, uefi::system_table *st)
{
uefi::boot_services *bs = st->boot_services;
uefi::runtime_services *rs = st->runtime_services;
status_line status {L"Performing UEFI pre-boot"};
hw::check_cpu_supported();
memory::init_pointer_fixup(bs, rs);
bootproto::args *args = new bootproto::args;
g_alloc.zero(args, sizeof(bootproto::args));
args->magic = bootproto::args_magic;
args->version = bootproto::args_version;
args->runtime_services = rs;
args->acpi_table = hw::find_acpi_table(st);
memory::mark_pointer_fixup(&args->runtime_services);
paging::allocate_tables(args);
return args;
}
/// Load the kernel and other programs from disk
void
load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs)
{
status_line status {L"Loading programs"};
fs::file disk = fs::get_boot_volume(image, bs);
fs::file bc_data = disk.open(L"jsix_boot.dat");
bootconfig bc {bc_data.load(), bs};
args->kernel = loader::load_program(disk, bc.kernel(), true);
args->init = loader::load_program(disk, bc.init());
namespace bits = util::bits;
using bootproto::desc_flags;
if (screen) {
video::make_module(screen);
// Go through the screen-specific descriptors first to
// give them priority
for (const descriptor &d : bc.programs()) {
if (!bits::has(d.flags, desc_flags::graphical))
continue;
if (bits::has(d.flags, desc_flags::panic))
args->panic = loader::load_program(disk, d);
else
loader::load_module(disk, d);
}
}
// Load the non-graphical descriptors
for (const descriptor &d : bc.programs()) {
if (bits::has(d.flags, desc_flags::graphical))
continue;
if (bits::has(d.flags, desc_flags::panic) && !args->panic)
args->panic = loader::load_program(disk, d);
else
loader::load_module(disk, d);
}
// For now the only data we load is the symbol table
for (const descriptor &d : bc.data()) {
if (!bits::has(d.flags, desc_flags::symbols))
continue;
util::buffer symbol_table = loader::load_file(disk, d);
args->symbol_table = symbol_table.pointer;
break;
}
loader::verify_kernel_header(*args->kernel);
}
memory::efi_mem_map
uefi_exit(bootproto::args *args, uefi::handle image, uefi::boot_services *bs)
{
status_line status {L"Exiting UEFI", nullptr, false};
memory::efi_mem_map map;
map.update(*bs);
args->mem_map = memory::build_kernel_map(map);
args->frame_blocks = memory::build_frame_blocks(args->mem_map);
map.update(*bs);
try_or_raise(
bs->exit_boot_services(image, map.key),
L"Failed to exit boot services");
return map;
}
} // namespace boot
/// The UEFI entrypoint for the loader.
extern "C" uefi::status
efi_main(uefi::handle image, uefi::system_table *st)
{
using namespace boot;
uefi::boot_services *bs = st->boot_services;
console con(st->con_out);
bootproto::allocation_register *allocs = nullptr;
bootproto::modules_page *modules = nullptr;
memory::allocator::init(allocs, modules, bs);
video::screen *screen = video::pick_mode(bs);
con.announce();
bootproto::args *args = uefi_preboot(image, st);
load_resources(args, screen, image, bs);
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
args->allocations = allocs;
args->modules = reinterpret_cast<uintptr_t>(modules);
status_bar status {screen}; // Switch to fb status display
// Map the kernel and panic handler to the appropriate addresses
paging::map_program(args, *args->kernel);
paging::map_program(args, *args->panic);
memory::fix_frame_blocks(args);
bootproto::entrypoint kentry =
reinterpret_cast<bootproto::entrypoint>(args->kernel->entrypoint);
//status.next();
hw::setup_control_regs();
memory::virtualize(args->pml4, map, st->runtime_services);
//status.next();
change_pointer(args);
change_pointer(args->pml4);
change_pointer(args->kernel);
change_pointer(args->kernel->sections.pointer);
change_pointer(args->init);
change_pointer(args->init->sections.pointer);
//status.next();
kentry(args);
debug_break();
return uefi::status::unsupported;
}