Add EFI stuff to the metadata
This commit is contained in:
parent
9e36a39444
commit
d53eb73e76
|
@ -34,7 +34,10 @@
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
packages = [ rust-uefi ];
|
packages = [
|
||||||
|
rust-uefi
|
||||||
|
pkgs.lldb
|
||||||
|
];
|
||||||
|
|
||||||
RUST_SRC_PATH = "${rust-uefi}/lib/rustlib/src/rust/library";
|
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::vec::Vec;
|
||||||
use alloc::{collections::BTreeMap, string::String};
|
use alloc::{collections::BTreeMap, string::String};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use uefi::prelude::BootServices;
|
use uefi::table::boot::MemoryMap;
|
||||||
use uefi::table::boot::MemoryType;
|
|
||||||
use uefi::{
|
use uefi::{
|
||||||
proto::console::gop::{GraphicsOutput, PixelFormat},
|
proto::console::gop::{GraphicsOutput, PixelFormat},
|
||||||
table::boot::PAGE_SIZE,
|
table::boot::PAGE_SIZE,
|
||||||
|
@ -123,53 +122,33 @@ struct EFIMemoryMapHeader {
|
||||||
descriptor_version: u32,
|
descriptor_version: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
impl Serialize for MemoryMap {
|
||||||
pub struct EFIMemoryMapParams {
|
fn alignment() -> usize {
|
||||||
header: EFIMemoryMapHeader,
|
4
|
||||||
map: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EFIMemoryMapParams {
|
fn size(&self) -> usize {
|
||||||
pub fn from_boot_services(bs: &BootServices) -> Self {
|
core::mem::size_of::<EFIMemoryMapHeader>() + self.as_raw().0.len()
|
||||||
let map = bs
|
}
|
||||||
.memory_map(MemoryType::LOADER_DATA)
|
|
||||||
.expect("Failed to get EFI memory map");
|
|
||||||
|
|
||||||
let (raw, meta) = map.as_raw();
|
fn serialize_raw(&self, out: &mut [u8]) {
|
||||||
|
let (raw, meta) = self.as_raw();
|
||||||
|
|
||||||
let header = EFIMemoryMapHeader {
|
let header = EFIMemoryMapHeader {
|
||||||
memory_size: meta.map_size,
|
memory_size: meta.map_size,
|
||||||
descriptor_size: meta.desc_size,
|
descriptor_size: meta.desc_size,
|
||||||
descriptor_version: meta.desc_version,
|
descriptor_version: meta.desc_version,
|
||||||
};
|
};
|
||||||
|
let header_size = core::mem::size_of_val(&header);
|
||||||
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_bytes = unsafe {
|
let header_bytes = unsafe {
|
||||||
core::slice::from_raw_parts(
|
core::slice::from_raw_parts(
|
||||||
&self.header as *const EFIMemoryMapHeader as *const u8,
|
&header as *const EFIMemoryMapHeader as *const u8,
|
||||||
header_size,
|
header_size,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
out[..header_size].copy_from_slice(header_bytes);
|
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
|
/// Value in the module info TLV
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum ModuleInfoValue {
|
pub enum ModuleInfoValue {
|
||||||
StaticString(&'static str),
|
StaticString(&'static str),
|
||||||
String(String),
|
String(String),
|
||||||
|
@ -288,7 +266,7 @@ pub enum ModuleInfoValue {
|
||||||
Buffer(Vec<u8>),
|
Buffer(Vec<u8>),
|
||||||
Howto(Howto),
|
Howto(Howto),
|
||||||
EFIFrameBuffer(EFIFramebufferParams),
|
EFIFrameBuffer(EFIFramebufferParams),
|
||||||
EFIMemoryMap(EFIMemoryMapParams),
|
EFIMemoryMap(MemoryMap),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInfoValue {
|
impl ModuleInfoValue {
|
||||||
|
@ -349,7 +327,7 @@ impl core::fmt::Debug for ModuleInfoValue {
|
||||||
|
|
||||||
/// Key and value in the module info TLV
|
/// Key and value in the module info TLV
|
||||||
/// TODO: figure out how to make this properly typesafe
|
/// TODO: figure out how to make this properly typesafe
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct ModuleInfoItem {
|
pub struct ModuleInfoItem {
|
||||||
pub tag: ModuleInfoType,
|
pub tag: ModuleInfoType,
|
||||||
pub value: ModuleInfoValue,
|
pub value: ModuleInfoValue,
|
||||||
|
|
66
src/boot.rs
66
src/boot.rs
|
@ -5,13 +5,25 @@ pub use x86_64::boot_kernel;
|
||||||
mod x86_64 {
|
mod x86_64 {
|
||||||
use core::{arch::global_asm, slice};
|
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::{
|
use x86_64::{
|
||||||
structures::paging::{PageTable, PageTableFlags},
|
structures::paging::{PageTable, PageTableFlags},
|
||||||
PhysAddr,
|
PhysAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{object::Kernel, staging::allocate_code};
|
use crate::{
|
||||||
|
abi::{EFIFramebufferParams, ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize},
|
||||||
|
object::Kernel,
|
||||||
|
staging::allocate_code,
|
||||||
|
};
|
||||||
|
|
||||||
global_asm!(
|
global_asm!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -67,6 +79,7 @@ trampoline_size:
|
||||||
kernel_base: *const u8,
|
kernel_base: *const u8,
|
||||||
modinfo_base: *const u8,
|
modinfo_base: *const u8,
|
||||||
free_ptr: *const u8,
|
free_ptr: *const u8,
|
||||||
|
staging: &mut [u8],
|
||||||
) {
|
) {
|
||||||
let misc_alloc = allocate_code(
|
let misc_alloc = allocate_code(
|
||||||
system_table.boot_services(),
|
system_table.boot_services(),
|
||||||
|
@ -113,6 +126,9 @@ trampoline_size:
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// Serialize some final metadata. Calls exit boot services.
|
||||||
|
add_efi_metadata(system_table, staging);
|
||||||
|
|
||||||
let trampoline_func: TrampolineFunction =
|
let trampoline_func: TrampolineFunction =
|
||||||
core::mem::transmute(misc_buf.trampoline.as_ptr());
|
core::mem::transmute(misc_buf.trampoline.as_ptr());
|
||||||
trampoline_func(
|
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;
|
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 alloc::{collections::btree_map::BTreeMap, string::ToString};
|
||||||
use log::info;
|
use log::info;
|
||||||
use object::{Kernel, Module};
|
use object::{Kernel, Module};
|
||||||
use uefi::{fs::FileSystem, prelude::*};
|
use uefi::{fs::FileSystem, prelude::*, proto::loaded_image::LoadedImage};
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
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");
|
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 kernel_data = {
|
||||||
let mut esp = FileSystem::new(
|
let mut esp = FileSystem::new(
|
||||||
system_table
|
system_table
|
||||||
|
@ -42,12 +52,12 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
||||||
"kernel".to_string(),
|
"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
|
let metadata_size: usize = kernel_metadata
|
||||||
.iter()
|
.iter()
|
||||||
.map(|item| item.alloc_size())
|
.map(|item| item.alloc_size())
|
||||||
.sum::<usize>()
|
.sum::<usize>()
|
||||||
+ 16 * 1024;
|
+ 1024 * 1024;
|
||||||
|
|
||||||
let alloc_size = kernel.alloc_size() + environment.alloc_size() + metadata_size;
|
let alloc_size = kernel.alloc_size() + environment.alloc_size() + metadata_size;
|
||||||
let staging = staging::allocate_code(system_table.boot_services(), alloc_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),
|
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) };
|
let free_ptr = unsafe { next.as_ptr().byte_add(metadata_size) };
|
||||||
kernel_metadata.push(ModuleInfoItem {
|
kernel_metadata.push(ModuleInfoItem {
|
||||||
|
@ -69,11 +82,19 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
||||||
value: ModuleInfoValue::Pointer(free_ptr),
|
value: ModuleInfoValue::Pointer(free_ptr),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let modinfo_base = next.as_ptr();
|
||||||
for item in kernel_metadata.iter() {
|
for item in kernel_metadata.iter() {
|
||||||
next = item.serialize_unaligned(next);
|
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
|
// boot_kernel shouldn't return
|
||||||
Status::ABORTED
|
Status::ABORTED
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl<'a> Kernel<'a> {
|
||||||
.copy_from_slice(&self.elf[in_offset..in_offset + copy_size]);
|
.copy_from_slice(&self.elf[in_offset..in_offset + copy_size]);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"kernel: {:x}@{:x} -> {:x}",
|
"kernel: {:#x}@{:#x} -> {:#x}",
|
||||||
copy_size,
|
copy_size,
|
||||||
in_offset,
|
in_offset,
|
||||||
(&out[out_offset] as *const u8) as usize
|
(&out[out_offset] as *const u8) as usize
|
||||||
|
|
Loading…
Reference in a new issue