Compare commits

...

2 commits

Author SHA1 Message Date
Artemis Tosini 405cdf8f26
Switch to goblin::elf 2024-08-04 00:19:06 +00:00
Artemis Tosini 0f2fa36333
Start parsing kernel 2024-08-04 00:12:40 +00:00
6 changed files with 294 additions and 20 deletions

45
Cargo.lock generated
View file

@ -20,27 +20,38 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "elf"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
[[package]]
name = "freeloader"
version = "0.1.0"
dependencies = [
"elf",
"goblin",
"log",
"uefi",
]
[[package]]
name = "goblin"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.86"
@ -79,6 +90,26 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "scroll"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.72",
]
[[package]]
name = "syn"
version = "1.0.109"

View file

@ -6,4 +6,4 @@ edition = "2021"
[dependencies]
uefi = { version = "0.29.0", default-features = false, features = [ "alloc", "global_allocator", "panic_handler", "logger" ] }
log = { version = "0.4.22", default-features = false }
elf = { version = "0.7.4", default_features = false }
goblin = { version = "0.8.2", default-features = false, features = [ "elf64", "elf32", "endian_fd" ] }

169
notes.md
View file

@ -40,3 +40,172 @@ Tons of arch-specific restrictions
* Pointers are passed as 32-bit, must be within the first 4G
* First 4G of virtual memory must be identity mapped
* Kernel virtual address must also be mapped to kernel (normally `0xffff_ffff_8000_0000`)
## Sample kernel
modinfo:
```
0xffffffff8282b000:
type: (0x01) MODINFO_NAME
len: 20
value: /boot/kernel/kernel
0xffffffff8282b020:
type: (0x02) MODINFO_TYPE
len: 11
value: elf kernel
0xffffffff8282b038:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff80200000
0xffffffff8282b048:
type: (0x04) MODINFO_SIZE
len: 8
value: 32731368
0xffffffff8282b058:
type: (0x9004) MODINFO_METADATA | MODINFOMD_EFI_MAP
len: 6080
value: buffer contents omitted
0xffffffff8282c820:
type: (0x9005) MODINFO_METADATA | MODINFOMD_EFI_FB
len: 48
value: 0x0000000084000000
0xffffffff8282c858:
type: (0x800d) MODINFO_METADATA | MODINFOMD_KEYBUF
len: 33028
value: buffer contents omitted
0xffffffff82834968:
type: (0x800c) MODINFO_METADATA | MODINFOMD_FW_HANDLE
len: 8
value: buffer contents omitted
0xffffffff82834978:
type: (0x9006) MODINFO_METADATA | MODINFOMD_MODULEP
len: 8
value:
0xffffffff82834988:
type: (0x8008) MODINFO_METADATA | MODINFOMD_KERNEND
len: 8
value: 0x0000000002837000
0xffffffff82834998:
type: (0x8006) MODINFO_METADATA | MODINFOMD_ENVP
len: 8
value: 0x000000000282a000
0xffffffff828349a8:
type: (0x8007) MODINFO_METADATA | MODINFOMD_HOWTO
len: 4
value: 0x20000000
0xffffffff828349b8:
type: (0x8002) MODINFO_METADATA | MODINFOMD_ELFHDR
len: 64
value: buffer contents omitted
0xffffffff82834a00:
type: (0x8005) MODINFO_METADATA | MODINFOMD_DYNAMIC
len: 8
value: 0xffffffff81600000
0xffffffff82834a10:
type: (0x8004) MODINFO_METADATA | MODINFOMD_ESYM
len: 8
value: 0xffffffff821370e8
0xffffffff82834a20:
type: (0x8003) MODINFO_METADATA | MODINFOMD_SSYM
len: 8
value: 0xffffffff81e00000
0xffffffff82834a30:
type: (0x8009) MODINFO_METADATA | MODINFOMD_SHDR
len: 3904
value: buffer contents omitted
0xffffffff82835978:
type: (0x01) MODINFO_NAME
len: 20
value: /boot/kernel/zfs.ko
0xffffffff82835998:
type: (0x02) MODINFO_TYPE
len: 15
value: elf obj module
0xffffffff828359b0:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff82138000
0xffffffff828359c0:
type: (0x04) MODINFO_SIZE
len: 8
value: 6084104
0xffffffff828359d0:
type: (0x8002) MODINFO_METADATA | MODINFOMD_ELFHDR
len: 64
value: buffer contents omitted
0xffffffff82835a18:
type: (0x8009) MODINFO_METADATA | MODINFOMD_SHDR
len: 1984
value: buffer contents omitted
0xffffffff828361e0:
type: (0x01) MODINFO_NAME
len: 26
value: /boot/kernel/cryptodev.ko
0xffffffff82836208:
type: (0x02) MODINFO_TYPE
len: 15
value: elf obj module
0xffffffff82836220:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff82706000
0xffffffff82836230:
type: (0x04) MODINFO_SIZE
len: 8
value: 30680
0xffffffff82836240:
type: (0x8002) MODINFO_METADATA | MODINFOMD_ELFHDR
len: 64
value: buffer contents omitted
0xffffffff82836288:
type: (0x8009) MODINFO_METADATA | MODINFOMD_SHDR
len: 1856
value: buffer contents omitted
0xffffffff828369d0:
type: (0x01) MODINFO_NAME
len: 12
value: /etc/hostid
0xffffffff828369e8:
type: (0x02) MODINFO_TYPE
len: 9
value: hostuuid
0xffffffff82836a00:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff8270d7d8
0xffffffff82836a10:
type: (0x04) MODINFO_SIZE
len: 8
value: 37
0xffffffff82836a20:
type: (0x01) MODINFO_NAME
len: 14
value: /boot/entropy
0xffffffff82836a38:
type: (0x02) MODINFO_TYPE
len: 19
value: boot_entropy_cache
0xffffffff82836a58:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff8270d7fd
0xffffffff82836a68:
type: (0x04) MODINFO_SIZE
len: 8
value: 4096
0xffffffff82836a78:
type: (0x01) MODINFO_NAME
len: 6
value: TSLOG
0xffffffff82836a88:
type: (0x02) MODINFO_TYPE
len: 11
value: TSLOG data
0xffffffff82836aa0:
type: (0x03) MODINFO_ADDR
len: 8
value: 0xffffffff8270e7fd
0xffffffff82836ab0:
type: (0x04) MODINFO_SIZE
len: 8
value: 1159497
```

View file

@ -181,8 +181,8 @@ impl Serialize for ModuleInfoValue {
/// TODO: figure out how to make this properly typesafe
#[derive(Debug, Clone)]
pub struct ModuleInfoItem {
tag: ModuleInfoType,
value: ModuleInfoValue,
pub tag: ModuleInfoType,
pub value: ModuleInfoValue,
}
impl Serialize for ModuleInfoItem {

View file

@ -2,10 +2,11 @@
#![no_std]
mod abi;
mod object;
mod staging;
use elf::endian::NativeEndian;
use log::info;
use object::{Kernel, Module};
use uefi::{fs::FileSystem, prelude::*};
#[entry]
@ -14,8 +15,6 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
info!("Starting freeloader");
let staging_buf = staging::allocate_staging(system_table.boot_services());
let mut esp = FileSystem::new(
system_table
.boot_services()
@ -23,18 +22,18 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
.expect("Failed to get ESP handle"),
);
let kernel = esp
let kernel_data = esp
.read(cstr16!("efi\\freebsd\\kernel"))
.expect("Failed to read kernel");
info!("Loaded kernel");
info!("Read kernel");
staging_buf[..kernel.len()].copy_from_slice(&kernel);
let kernel = Kernel::from_elf_bytes(&kernel_data);
let header =
elf::ElfBytes::<NativeEndian>::minimal_parse(staging_buf).expect("Failed to parse kernel");
info!("Kernel is {:?}", header.ehdr.class);
info!(
"Kernel metadata is {:#?}",
kernel.metadata(core::ptr::null::<u8>())
);
loop {
system_table.boot_services().stall(10_000_000);

75
src/object.rs Normal file
View file

@ -0,0 +1,75 @@
extern crate alloc;
use crate::abi::{ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize};
use alloc::vec::Vec;
use goblin::elf::Elf;
use log::info;
#[cfg(target_arch = "x86_64")]
const NATIVE_ELF_MACHINE: u16 = goblin::elf::header::EM_X86_64;
pub trait Module {
/// Associated metadata for this module, including name and type
fn metadata(&self, load_address: *const u8) -> Vec<ModuleInfoItem>;
}
pub struct Kernel<'a> {
/// Full ELF
elf: &'a [u8],
/// Parsed ELF
parsed: Elf<'a>,
/// Raw ELF header bytes
elf_header: &'a [u8],
}
impl<'a> Kernel<'a> {
pub fn from_elf_bytes(elf: &'a [u8]) -> Self {
let parsed = Elf::parse(elf).expect("Failed to parse kernel");
if parsed.header.e_machine != NATIVE_ELF_MACHINE {
panic!("Kernel has wrong ELF machine");
}
let header_size = if parsed.is_64 { 0x40 } else { 0x34 };
let elf_header = &elf[..header_size];
Self {
elf,
parsed,
elf_header,
}
}
}
impl<'a> Serialize for Kernel<'a> {
fn alignment() -> usize {
// On some platforms we need to be aligned to a level 2 page
2 * 1024 * 1024
}
fn size(&self) -> usize {
todo!()
}
fn serialize(&self, out: &mut [u8]) {
todo!()
}
}
impl<'a> Module for Kernel<'a> {
fn metadata(&self, load_address: *const u8) -> Vec<ModuleInfoItem> {
alloc::vec![
ModuleInfoItem {
tag: ModuleInfoType::Name,
value: ModuleInfoValue::StaticString("/boot/kernel/kernel")
},
ModuleInfoItem {
tag: ModuleInfoType::Type,
value: ModuleInfoValue::StaticString("elf kernel")
},
ModuleInfoItem {
tag: ModuleInfoType::ElfHeader,
value: ModuleInfoValue::Buffer(self.elf_header.to_vec())
},
]
}
}