Add EFI stuff to the metadata
This commit is contained in:
parent
9e36a39444
commit
d53eb73e76
|
@ -34,7 +34,10 @@
|
|||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
packages = [ rust-uefi ];
|
||||
packages = [
|
||||
rust-uefi
|
||||
pkgs.lldb
|
||||
];
|
||||
|
||||
RUST_SRC_PATH = "${rust-uefi}/lib/rustlib/src/rust/library";
|
||||
};
|
||||
|
|
50
src/abi.rs
50
src/abi.rs
|
@ -2,8 +2,7 @@ extern crate alloc;
|
|||
use alloc::vec::Vec;
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
use bitflags::bitflags;
|
||||
use uefi::prelude::BootServices;
|
||||
use uefi::table::boot::MemoryType;
|
||||
use uefi::table::boot::MemoryMap;
|
||||
use uefi::{
|
||||
proto::console::gop::{GraphicsOutput, PixelFormat},
|
||||
table::boot::PAGE_SIZE,
|
||||
|
@ -123,53 +122,33 @@ struct EFIMemoryMapHeader {
|
|||
descriptor_version: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EFIMemoryMapParams {
|
||||
header: EFIMemoryMapHeader,
|
||||
map: Vec<u8>,
|
||||
impl Serialize for MemoryMap {
|
||||
fn alignment() -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
impl EFIMemoryMapParams {
|
||||
pub fn from_boot_services(bs: &BootServices) -> Self {
|
||||
let map = bs
|
||||
.memory_map(MemoryType::LOADER_DATA)
|
||||
.expect("Failed to get EFI memory map");
|
||||
fn size(&self) -> usize {
|
||||
core::mem::size_of::<EFIMemoryMapHeader>() + self.as_raw().0.len()
|
||||
}
|
||||
|
||||
let (raw, meta) = map.as_raw();
|
||||
fn serialize_raw(&self, out: &mut [u8]) {
|
||||
let (raw, meta) = self.as_raw();
|
||||
|
||||
let header = EFIMemoryMapHeader {
|
||||
memory_size: meta.map_size,
|
||||
descriptor_size: meta.desc_size,
|
||||
descriptor_version: meta.desc_version,
|
||||
};
|
||||
|
||||
Self {
|
||||
header,
|
||||
map: raw.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for EFIMemoryMapParams {
|
||||
fn alignment() -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
core::mem::size_of::<EFIMemoryMapHeader>() + self.map.len()
|
||||
}
|
||||
|
||||
fn serialize_raw(&self, out: &mut [u8]) {
|
||||
let header_size = core::mem::size_of_val(&self.header);
|
||||
let header_size = core::mem::size_of_val(&header);
|
||||
let header_bytes = unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
&self.header as *const EFIMemoryMapHeader as *const u8,
|
||||
&header as *const EFIMemoryMapHeader as *const u8,
|
||||
header_size,
|
||||
)
|
||||
};
|
||||
|
||||
out[..header_size].copy_from_slice(header_bytes);
|
||||
out[header_size..].copy_from_slice(&self.map);
|
||||
out[header_size..].copy_from_slice(raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +258,6 @@ pub enum ModuleInfoType {
|
|||
}
|
||||
|
||||
/// Value in the module info TLV
|
||||
#[derive(Clone)]
|
||||
pub enum ModuleInfoValue {
|
||||
StaticString(&'static str),
|
||||
String(String),
|
||||
|
@ -288,7 +266,7 @@ pub enum ModuleInfoValue {
|
|||
Buffer(Vec<u8>),
|
||||
Howto(Howto),
|
||||
EFIFrameBuffer(EFIFramebufferParams),
|
||||
EFIMemoryMap(EFIMemoryMapParams),
|
||||
EFIMemoryMap(MemoryMap),
|
||||
}
|
||||
|
||||
impl ModuleInfoValue {
|
||||
|
@ -349,7 +327,7 @@ impl core::fmt::Debug for ModuleInfoValue {
|
|||
|
||||
/// Key and value in the module info TLV
|
||||
/// TODO: figure out how to make this properly typesafe
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleInfoItem {
|
||||
pub tag: ModuleInfoType,
|
||||
pub value: ModuleInfoValue,
|
||||
|
|
66
src/boot.rs
66
src/boot.rs
|
@ -5,13 +5,25 @@ pub use x86_64::boot_kernel;
|
|||
mod x86_64 {
|
||||
use core::{arch::global_asm, slice};
|
||||
|
||||
use uefi::table::{boot::PAGE_SIZE, Boot, SystemTable};
|
||||
use log::warn;
|
||||
use uefi::{
|
||||
prelude::BootServices,
|
||||
proto::console::gop::GraphicsOutput,
|
||||
table::{
|
||||
boot::{MemoryType, PAGE_SIZE},
|
||||
Boot, SystemTable,
|
||||
},
|
||||
};
|
||||
use x86_64::{
|
||||
structures::paging::{PageTable, PageTableFlags},
|
||||
PhysAddr,
|
||||
};
|
||||
|
||||
use crate::{object::Kernel, staging::allocate_code};
|
||||
use crate::{
|
||||
abi::{EFIFramebufferParams, ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize},
|
||||
object::Kernel,
|
||||
staging::allocate_code,
|
||||
};
|
||||
|
||||
global_asm!(
|
||||
r#"
|
||||
|
@ -67,6 +79,7 @@ trampoline_size:
|
|||
kernel_base: *const u8,
|
||||
modinfo_base: *const u8,
|
||||
free_ptr: *const u8,
|
||||
staging: &mut [u8],
|
||||
) {
|
||||
let misc_alloc = allocate_code(
|
||||
system_table.boot_services(),
|
||||
|
@ -113,6 +126,9 @@ trampoline_size:
|
|||
);
|
||||
|
||||
unsafe {
|
||||
// Serialize some final metadata. Calls exit boot services.
|
||||
add_efi_metadata(system_table, staging);
|
||||
|
||||
let trampoline_func: TrampolineFunction =
|
||||
core::mem::transmute(misc_buf.trampoline.as_ptr());
|
||||
trampoline_func(
|
||||
|
@ -124,4 +140,50 @@ trampoline_size:
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn add_efi_metadata(boot_system_table: SystemTable<Boot>, mut staging: &mut [u8]) {
|
||||
staging = add_efi_framebuffer_metadata(boot_system_table.boot_services(), staging);
|
||||
|
||||
let (runtime_system_table, memory_map) =
|
||||
boot_system_table.exit_boot_services(MemoryType::LOADER_DATA);
|
||||
let memory_map_item = ModuleInfoItem {
|
||||
tag: ModuleInfoType::EFIMemoryMap,
|
||||
value: ModuleInfoValue::EFIMemoryMap(memory_map),
|
||||
};
|
||||
staging = memory_map_item.serialize_unaligned(staging);
|
||||
|
||||
let firmware_handle_item = ModuleInfoItem {
|
||||
tag: ModuleInfoType::FirmwareHandle,
|
||||
value: ModuleInfoValue::Pointer(runtime_system_table.as_ptr() as *const u8),
|
||||
};
|
||||
let _staging = firmware_handle_item.serialize_unaligned(staging);
|
||||
}
|
||||
|
||||
fn add_efi_framebuffer_metadata<'a>(
|
||||
boot_services: &BootServices,
|
||||
staging: &'a mut [u8],
|
||||
) -> &'a mut [u8] {
|
||||
let params = match parse_efi_framebuffer_params(boot_services) {
|
||||
Ok(params) => params,
|
||||
Err(err) => {
|
||||
warn!("Unable to parse framebuffer parameters: {}", err);
|
||||
return staging;
|
||||
}
|
||||
};
|
||||
|
||||
let item = ModuleInfoItem {
|
||||
tag: ModuleInfoType::EFIFrameBuffer,
|
||||
value: ModuleInfoValue::EFIFrameBuffer(params),
|
||||
};
|
||||
|
||||
item.serialize_unaligned(staging)
|
||||
}
|
||||
fn parse_efi_framebuffer_params<'a>(
|
||||
boot_services: &BootServices,
|
||||
) -> Result<EFIFramebufferParams, uefi::Error> {
|
||||
let gop_handle = boot_services.get_handle_for_protocol::<GraphicsOutput>()?;
|
||||
let mut gop = boot_services.open_protocol_exclusive::<GraphicsOutput>(gop_handle)?;
|
||||
EFIFramebufferParams::from_graphics_output(&mut gop)
|
||||
.ok_or_else(|| uefi::Error::new(uefi::Status::INVALID_PARAMETER, ()))
|
||||
}
|
||||
}
|
||||
|
|
33
src/main.rs
33
src/main.rs
|
@ -8,11 +8,11 @@ mod staging;
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use abi::{Environment, ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize};
|
||||
use abi::{Environment, Howto, ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize};
|
||||
use alloc::{collections::btree_map::BTreeMap, string::ToString};
|
||||
use log::info;
|
||||
use object::{Kernel, Module};
|
||||
use uefi::{fs::FileSystem, prelude::*};
|
||||
use uefi::{fs::FileSystem, prelude::*, proto::loaded_image::LoadedImage};
|
||||
|
||||
#[entry]
|
||||
fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
||||
|
@ -20,6 +20,16 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
|
||||
info!("Starting freeloader");
|
||||
|
||||
{
|
||||
let loaded_image_protocol = system_table
|
||||
.boot_services()
|
||||
.open_protocol_exclusive::<LoadedImage>(image_handle)
|
||||
.expect("Failed to open LoadedImage protocol");
|
||||
let (base, size) = loaded_image_protocol.info();
|
||||
log::debug!("Image base: {:#x}, size: {:#x}", base as usize, size);
|
||||
log::debug!("Main is at {:#x}", &main as *const _ as usize)
|
||||
}
|
||||
|
||||
let kernel_data = {
|
||||
let mut esp = FileSystem::new(
|
||||
system_table
|
||||
|
@ -42,12 +52,12 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
"kernel".to_string(),
|
||||
)]));
|
||||
|
||||
// Allocate an extra 16KiB for items we have to add to metadata
|
||||
// Allocate an extra 1 MiB for items we have to add to metadata, like memory map
|
||||
let metadata_size: usize = kernel_metadata
|
||||
.iter()
|
||||
.map(|item| item.alloc_size())
|
||||
.sum::<usize>()
|
||||
+ 16 * 1024;
|
||||
+ 1024 * 1024;
|
||||
|
||||
let alloc_size = kernel.alloc_size() + environment.alloc_size() + metadata_size;
|
||||
let staging = staging::allocate_code(system_table.boot_services(), alloc_size);
|
||||
|
@ -61,7 +71,10 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
value: ModuleInfoValue::Pointer(environ_base),
|
||||
});
|
||||
|
||||
let modinfo_base = next.as_ptr();
|
||||
kernel_metadata.push(abi::ModuleInfoItem {
|
||||
tag: ModuleInfoType::Howto,
|
||||
value: ModuleInfoValue::Howto(Howto::VERBOSE | Howto::SERIAL),
|
||||
});
|
||||
|
||||
let free_ptr = unsafe { next.as_ptr().byte_add(metadata_size) };
|
||||
kernel_metadata.push(ModuleInfoItem {
|
||||
|
@ -69,11 +82,19 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
value: ModuleInfoValue::Pointer(free_ptr),
|
||||
});
|
||||
|
||||
let modinfo_base = next.as_ptr();
|
||||
for item in kernel_metadata.iter() {
|
||||
next = item.serialize_unaligned(next);
|
||||
}
|
||||
|
||||
boot::boot_kernel(system_table, kernel, kernel_base, modinfo_base, free_ptr);
|
||||
boot::boot_kernel(
|
||||
system_table,
|
||||
kernel,
|
||||
kernel_base,
|
||||
modinfo_base,
|
||||
free_ptr,
|
||||
next,
|
||||
);
|
||||
|
||||
// boot_kernel shouldn't return
|
||||
Status::ABORTED
|
||||
|
|
|
@ -91,7 +91,7 @@ impl<'a> Kernel<'a> {
|
|||
.copy_from_slice(&self.elf[in_offset..in_offset + copy_size]);
|
||||
|
||||
debug!(
|
||||
"kernel: {:x}@{:x} -> {:x}",
|
||||
"kernel: {:#x}@{:#x} -> {:#x}",
|
||||
copy_size,
|
||||
in_offset,
|
||||
(&out[out_offset] as *const u8) as usize
|
||||
|
|
Loading…
Reference in a new issue