After exiting UEFI, the bootloader had no way of displaying status to the user. Now it will display a series of small boxes as a progress bar along the bottom of the screen if a framebuffer exists. Errors or warnings during a step will cause that step's box to turn red or orange, and display bars above it to signal the error code. This caused the simplification of the error handling system (which was mostly just calling status_line::fail) and added different types of status objects.
111 lines
2.7 KiB
C++
111 lines
2.7 KiB
C++
#include <uefi/boot_services.h>
|
|
#include <uefi/types.h>
|
|
|
|
#include "loader.h"
|
|
#include "console.h"
|
|
#include "elf.h"
|
|
#include "error.h"
|
|
#include "fs.h"
|
|
#include "memory.h"
|
|
#include "paging.h"
|
|
#include "status.h"
|
|
|
|
namespace args = kernel::args;
|
|
|
|
namespace boot {
|
|
namespace loader {
|
|
|
|
buffer
|
|
load_file(
|
|
fs::file &disk,
|
|
const wchar_t *name,
|
|
const wchar_t *path,
|
|
uefi::memory_type type)
|
|
{
|
|
status_line status(L"Loading file", name);
|
|
|
|
fs::file file = disk.open(path);
|
|
buffer b = file.load(type);
|
|
|
|
console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
|
return b;
|
|
}
|
|
|
|
|
|
static bool
|
|
is_elfheader_valid(const elf::header *header)
|
|
{
|
|
return
|
|
header->magic[0] == 0x7f &&
|
|
header->magic[1] == 'E' &&
|
|
header->magic[2] == 'L' &&
|
|
header->magic[3] == 'F' &&
|
|
header->word_size == elf::word_size &&
|
|
header->endianness == elf::endianness &&
|
|
header->os_abi == elf::os_abi &&
|
|
header->machine == elf::machine &&
|
|
header->header_version == elf::version;
|
|
}
|
|
|
|
void
|
|
load_program(
|
|
args::program &program,
|
|
const wchar_t *name,
|
|
buffer data,
|
|
uefi::boot_services *bs)
|
|
{
|
|
status_line status(L"Loading program:", name);
|
|
const elf::header *header = reinterpret_cast<const elf::header*>(data.data);
|
|
|
|
if (data.size < sizeof(elf::header) || !is_elfheader_valid(header))
|
|
error::raise(uefi::status::load_error, L"ELF file not valid");
|
|
|
|
uintptr_t prog_base = uintptr_t(-1);
|
|
uintptr_t prog_end = 0;
|
|
|
|
for (int i = 0; i < header->ph_num; ++i) {
|
|
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
|
const elf::program_header *pheader =
|
|
offset_ptr<elf::program_header>(data.data, offset);
|
|
|
|
if (pheader->type != elf::PT_LOAD)
|
|
continue;
|
|
|
|
uintptr_t end = pheader->vaddr + pheader->mem_size;
|
|
if (pheader->vaddr < prog_base) prog_base = pheader->vaddr;
|
|
if (end > prog_end) prog_end = end;
|
|
}
|
|
|
|
size_t total_size = prog_end - prog_base;
|
|
size_t num_pages = memory::bytes_to_pages(total_size);
|
|
void *pages = nullptr;
|
|
|
|
try_or_raise(
|
|
bs->allocate_pages(uefi::allocate_type::any_pages,
|
|
memory::program_type, num_pages, &pages),
|
|
L"Failed allocating space for program");
|
|
|
|
bs->set_mem(pages, total_size, 0);
|
|
|
|
for (int i = 0; i < header->ph_num; ++i) {
|
|
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
|
const elf::program_header *pheader =
|
|
offset_ptr<elf::program_header>(data.data, offset);
|
|
|
|
if (pheader->type != elf::PT_LOAD)
|
|
continue;
|
|
|
|
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
|
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
|
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
|
}
|
|
|
|
program.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
|
program.size = total_size;
|
|
program.virt_addr = prog_base;
|
|
program.entrypoint = header->entrypoint;
|
|
}
|
|
|
|
} // namespace loader
|
|
} // namespace boot
|