[boot] Only allocate memory map once

The `build_kernel_mem_map` function now calls `get_uefi_mappings`
itself, instead of having the efi map passed in. `get_uefi_mappings`
also now takes a `bool allocate` to direct it to actually allocate
the map or not. If it doesn't, it instead just returns the size of
the map and the metadata - which `build_kernel_mem_map`	uses to decide
how much space to first allocate for the kernel's map.
This commit is contained in:
Justin C. Miller
2020-05-16 18:48:28 -07:00
parent 2adef874ee
commit 42dfa6ccfe
3 changed files with 32 additions and 142 deletions

View File

@@ -15,15 +15,8 @@
#include "memory.h"
#include "kernel_args.h"
/*
#include "guids.h"
#include "loader.h"
#include "utility.h"
#ifndef SCRATCH_PAGES
#define SCRATCH_PAGES 64
#endif
#define KERNEL_HEADER_MAGIC 0x600db007
#define KERNEL_HEADER_VERSION 1
@@ -171,115 +164,10 @@ bootloader_main_uefi(uefi::handle image, uefi::system_table *st, console &con, s
loader::loaded_elf kernel_elf =
loader::load(kernel->location, kernel->size, bs);
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;
*map_key = memory::build_kernel_mem_map(args, bs);
return kernel_elf;
}
/*
struct loader_data load;
load.data_length = data_length;
status = loader_load_kernel(bootsvc, &load);
CHECK_EFI_STATUS_OR_FAIL(status);
console::print(L" %x image bytes at 0x%x\r\n", load.kernel_length, load.kernel);
console::print(L" %x data bytes at 0x%x\r\n", load.data_length, load.data);
console::print(L" %x initrd bytes at 0x%x\r\n", load.initrd_length, load.initrd);
struct kernel_header *version = (struct kernel_header *)load.kernel;
if (version->magic != KERNEL_HEADER_MAGIC) {
console::print(L" bad magic %x\r\n", version->magic);
CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR);
}
console::print(L" Kernel version %d.%d.%d %x%s\r\n",
version->major, version->minor, version->patch, version->gitsha & 0x0fffffff,
version->gitsha & 0xf0000000 ? L"*" : L"");
console::print(L" Entrypoint 0x%x\r\n", load.kernel_entry);
kernel_entry kernel_main =
reinterpret_cast<kernel_entry>(load.kernel_entry);
memory_mark_pointer_fixup((void **)&kernel_main);
// Set up the kernel data pages to pass to the kernel
//
struct kernel_args *data_header = (struct kernel_args *)load.data;
memory_mark_pointer_fixup((void **)&data_header);
data_header->magic = DATA_HEADER_MAGIC;
data_header->version = DATA_HEADER_VERSION;
data_header->length = sizeof(struct kernel_args);
data_header->scratch_pages = SCRATCH_PAGES;
data_header->flags = 0;
data_header->initrd = load.initrd;
data_header->initrd_length = load.initrd_length;
memory_mark_pointer_fixup((void **)&data_header->initrd);
data_header->data = load.data;
data_header->data_length = load.data_length;
memory_mark_pointer_fixup((void **)&data_header->data);
data_header->memory_map = (EFI_MEMORY_DESCRIPTOR *)(data_header + 1);
memory_mark_pointer_fixup((void **)&data_header->memory_map);
data_header->runtime = runsvc;
memory_mark_pointer_fixup((void **)&data_header->runtime);
data_header->acpi_table = acpi_table;
memory_mark_pointer_fixup((void **)&data_header->acpi_table);
data_header->_reserved0 = 0;
data_header->_reserved1 = 0;
// Figure out the framebuffer (if any) and add that to the data header
//
status = con_get_framebuffer(
bootsvc,
&data_header->frame_buffer,
&data_header->frame_buffer_length,
&data_header->hres,
&data_header->vres,
&data_header->rmask,
&data_header->gmask,
&data_header->bmask);
CHECK_EFI_STATUS_OR_FAIL(status);
memory_mark_pointer_fixup((void **)&data_header->frame_buffer);
// Save the memory map and tell the firmware we're taking control.
//
struct memory_map map;
map.length = (load.data_length - header_size);
map.entries =
reinterpret_cast<EFI_MEMORY_DESCRIPTOR *>(data_header->memory_map);
status = memory_get_map(bootsvc, &map);
CHECK_EFI_STATUS_OR_FAIL(status);
data_header->memory_map_length = map.length;
data_header->memory_map_desc_size = map.size;
detect_debug_mode(runsvc, data_header);
// bootsvc->Stall(5000000);
status = bootsvc->ExitBootServices(image_handle, map.key);
CHECK_EFI_STATUS_OR_ASSERT(status, 0);
memory_virtualize(runsvc, &map);
// Hand control to the kernel
//
kernel_main(data_header);
return EFI_LOAD_ERROR;
}
*/
} // namespace boot
/// The UEFI entrypoint for the loader.

View File

@@ -161,47 +161,43 @@ can_merge(mem_entry &prev, mem_type type, uefi::memory_descriptor *next)
}
efi_mem_map
get_uefi_mappings(uefi::boot_services *bs)
get_uefi_mappings(bool allocate, uefi::boot_services *bs)
{
status_line(L"Getting UEFI memory map");
efi_mem_map map;
size_t needs_size = 0;
size_t map_key = 0;
size_t desc_size = 0;
uint32_t desc_version = 0;
uefi::status status = bs->get_memory_map(
&needs_size, nullptr, &map_key, &desc_size, &desc_version);
&needs_size, nullptr, &map.key, &map.size, &map.version);
if (status != uefi::status::buffer_too_small)
error::raise(status, L"Error getting memory map size");
size_t buffer_size = needs_size + 10*desc_size;
uefi::memory_descriptor *buffer = nullptr;
try_or_raise(
bs->allocate_pool(
uefi::memory_type::loader_data, buffer_size,
reinterpret_cast<void**>(&buffer)),
L"Allocating space for memory map");
if (allocate) {
map.length = needs_size + 10*map.size;
try_or_raise(
bs->get_memory_map(&buffer_size, buffer, &map_key, &desc_size, &desc_version),
L"Getting UEFI memory map");
try_or_raise(
bs->allocate_pool(
uefi::memory_type::loader_data, map.length,
reinterpret_cast<void**>(&map.entries)),
L"Allocating space for memory map");
try_or_raise(
bs->get_memory_map(&map.length, map.entries, &map.key, &map.size, &map.version),
L"Getting UEFI memory map");
}
efi_mem_map map;
map.length = buffer_size;
map.size = desc_size;
map.key = map_key;
map.version = desc_version;
map.entries = buffer;
return map;
}
void
build_kernel_mem_map(efi_mem_map &efi_map, kernel::args::header *args, uefi::boot_services *bs)
size_t
build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
{
status_line(L"Creating kernel memory map");
efi_mem_map efi_map = get_uefi_mappings(false, bs);
size_t map_size = efi_map.num_entries() * sizeof(mem_entry);
kernel::args::mem_entry *kernel_map = nullptr;
try_or_raise(
@@ -213,6 +209,7 @@ build_kernel_mem_map(efi_mem_map &efi_map, kernel::args::header *args, uefi::boo
L"Error allocating kernel memory map module space.");
bs->set_mem(kernel_map, map_size, 0);
efi_map = get_uefi_mappings(true, bs);
size_t i = 0;
bool first = true;
@@ -312,6 +309,8 @@ build_kernel_mem_map(efi_mem_map &efi_map, kernel::args::header *args, uefi::boo
ent.start, ent.attr, ent.type, ent.pages);
}
*/
return efi_map.key;
}

View File

@@ -68,6 +68,8 @@ struct efi_mem_map
uint32_t version; ///< Version of the `memory_descriptor` struct
desc *entries; ///< The array of UEFI descriptors
efi_mem_map() : length(0), size(0), key(0), version(0), entries(nullptr) {}
/// Get the count of entries in the array
inline size_t num_entries() const { return length / size; }
@@ -79,13 +81,14 @@ struct efi_mem_map
};
/// Get the memory map from UEFI.
efi_mem_map get_uefi_mappings(uefi::boot_services *bs);
/// \arg allocate If false, don't actually fetch the mappings, just
/// return a structure describing them.
efi_mem_map get_uefi_mappings(bool allocate, uefi::boot_services *bs);
/// Add the kernel's memory map as a module to the kernel args.
void build_kernel_mem_map(
efi_mem_map &efi_map,
kernel::args::header *args,
uefi::boot_services *bs);
/// \returns The uefi memory map key for the version used to build
/// this map
size_t build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs);
} // namespace boot
} // namespace memory