[boot] Improve bootloader allocation accounting

The bootloader relied on the kernel to know which parts of memory to not
allocate over. For the future shift of having the init process load
other processes instead of the kernel, the bootloader needs a mechanism
to just hand the kernel a list of allocations. This is now done through
the new bootloader allocator, which all allocation goes through. Pool
memory will not be tracked, and so can be overwritten - this means the
args structure and its other structures like programs need to be handled
right away, or copied by the kernel.

- Add bootloader allocator
- Implement a new linked-list based set of pages that act as allocation
  registers
- Allow for operator new in the bootloader, which goes through the
  global allocator for pool memory
- Split memory map and frame accouting code in the bootloader into
  separate memory_map.* files
- Remove many includes that could be replaced by forward declaration in
  the bootloader
- Add a new global template type, `counted`, which replaces the
  bootloader's `buffer` type, and updated kernel args structure to use it.
- Move bootloader's pointer_manipulation.h to the global include dir
- Make offset_iterator try to return references instead of pointers to
  make it more consistent with static array iteration
- Implement a stub atexit() in the bootloader to satisfy clang
This commit is contained in:
Justin C. Miller
2021-07-25 16:51:10 -07:00
parent 12e893e11f
commit 0b2df134ce
24 changed files with 826 additions and 609 deletions

63
src/boot/memory_map.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
/// \file memory_map.h
/// Memory-map related types and functions
#include "counted.h"
#include "pointer_manipulation.h"
namespace uefi {
struct boot_services;
struct memory_descriptor;
}
namespace kernel {
namespace init {
struct args;
struct frame_block;
struct mem_entry;
}}
namespace boot {
namespace memory {
/// Struct that represents UEFI's memory map. Contains a pointer to the map data
/// as well as the data on how to read it.
struct efi_mem_map
{
using desc = uefi::memory_descriptor;
using iterator = offset_iterator<desc>;
size_t length; ///< Total length of the map data
size_t total; ///< Total allocated space for map data
size_t size; ///< Size of an entry in the array
size_t key; ///< Key for detecting changes
uint32_t version; ///< Version of the `memory_descriptor` struct
desc *entries; ///< The array of UEFI descriptors
efi_mem_map() : length(0), total(0), size(0), key(0), version(0), entries(nullptr) {}
/// Update the map from UEFI
void update(uefi::boot_services &bs);
/// Get the count of entries in the array
inline size_t num_entries() const { return length / size; }
/// Return an iterator to the beginning of the array
inline iterator begin() { return iterator(entries, size); }
/// Return an iterator to the end of the array
inline iterator end() { return offset_ptr<desc>(entries, length); }
};
/// Add the kernel's memory map as a module to the kernel args.
/// \returns The uefi memory map used to build the kernel map
counted<kernel::init::mem_entry> build_kernel_map(efi_mem_map &map);
/// Create the kernel frame allocation maps
counted<kernel::init::frame_block> build_frame_blocks(const counted<kernel::init::mem_entry> &kmap);
/// Map the frame allocation maps to the right spot and fix up pointers
void fix_frame_blocks(kernel::init::args *args);
} // namespace boot
} // namespace memory