[boot] Fix call to exit_boot_services

Exiting boot services can't actually be done from inside
`bootloader_uefi_main`, because there are objects in that scope that run
code requiring boot services in their destructors.

Also added `support.cpp` with `memcpy` because clang will emit
references to `memcpy` even in freestanding mode.

Added a `debug_break` function to allow for faking breakpoints when
connecting to the bootloader with GDB.

Tags: debug
This commit is contained in:
Justin C. Miller
2020-05-13 02:08:47 -07:00
parent 2bd91c2d94
commit a6e4995963
7 changed files with 50 additions and 6 deletions

View File

@@ -89,6 +89,8 @@ cpu_assert_handler::handle(uefi::status s, const wchar_t *message)
} // namespace error
} // namespace boot
extern "C" int _purecall() { ::boot::error::raise(uefi::status::unsupported, L"Pure virtual call"); }
void operator delete (void *) {}
void debug_break()
{
volatile int go = 0;
while (!go);
}

View File

@@ -58,6 +58,9 @@ public:
} // namespace error
} // namespace boot
/// Debugging psuedo-breakpoint.
void debug_break();
/// Helper macro to raise an error if an operation fails.
/// \arg s An expression evaluating to a UEFI status
/// \arg m The error message to use on failure

View File

@@ -144,7 +144,7 @@ load_module(
/// UEFI is still in control of the machine. (ie, while the loader still
/// has access to boot services.
loader::loaded_elf
bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con)
bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con, size_t *map_key)
{
error::uefi_handler handler(con);
@@ -174,6 +174,9 @@ bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con)
memory::efi_mem_map efi_map = memory::get_uefi_mappings(bs);
memory::build_kernel_mem_map(efi_map, args, bs);
efi_map = memory::get_uefi_mappings(bs);
*map_key = efi_map.key;
return kernel_elf;
}
@@ -288,10 +291,15 @@ efi_main(uefi::handle image_handle, uefi::system_table *st)
error::cpu_assert_handler handler;
console con(st->boot_services, st->con_out);
size_t map_key;
loader::loaded_elf kernel =
bootloader_main_uefi(image_handle, st, con);
bootloader_main_uefi(image_handle, st, con, &map_key);
while(1);
try_or_raise(
st->boot_services->exit_boot_services(image_handle, map_key),
L"Failed to exit boot services");
debug_break();
return uefi::status::unsupported;
}

View File

@@ -67,6 +67,8 @@ init_pointer_fixup(uefi::boot_services *bs, uefi::runtime_services *rs)
status_line status(L"Initializing pointer virtualization event");
uefi::event event;
bs->set_mem(&fixup_pointers, sizeof(fixup_pointers), 0);
fixup_pointer_index = 0;
try_or_raise(
bs->create_event(

27
src/boot/support.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include <stdint.h>
#include "error.h"
extern "C" {
/// Basic memcpy() implementation for clang. Clang requires freestanding code
/// implement memcpy(), as it may emit references to it. This basic memcpy is
/// not the most efficient, but will get linked if no other memcpy exists.
__attribute__ ((__weak__))
void *memcpy(void *dest, const void *src, size_t n)
{
uint8_t *cdest = reinterpret_cast<uint8_t*>(dest);
const uint8_t *csrc = reinterpret_cast<const uint8_t*>(src);
for (size_t i = 0; i < n; ++i)
cdest[i] = csrc[i];
return dest;
}
int _purecall()
{
::boot::error::raise(uefi::status::unsupported, L"Pure virtual call");
}
} // extern "C"
void operator delete (void *) {}