Start parsing kernel

This commit is contained in:
Artemis Tosini 2024-08-04 00:12:40 +00:00
parent 5a86c41d07
commit 0f2fa36333
Signed by: artemist
GPG key ID: EE5227935FE3FF18
4 changed files with 260 additions and 12 deletions

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);

80
src/object.rs Normal file
View file

@ -0,0 +1,80 @@
extern crate alloc;
use crate::abi::{ModuleInfoItem, ModuleInfoType, ModuleInfoValue, Serialize};
use alloc::vec::Vec;
use elf::{endian::NativeEndian, ElfBytes};
use log::info;
#[cfg(target_arch = "x86_64")]
const NATIVE_ELF_MACHINE: u16 = elf::abi::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: ElfBytes<'a, NativeEndian>,
/// Raw ELF header bytes
elf_header: &'a [u8],
}
impl<'a> Kernel<'a> {
pub fn from_elf_bytes(elf: &'a [u8]) -> Self {
let parsed =
elf::ElfBytes::<NativeEndian>::minimal_parse(elf).expect("Failed to parse kernel");
info!("Kernel is {:?}", parsed.ehdr.class);
if parsed.ehdr.e_machine != NATIVE_ELF_MACHINE {
panic!("Kernel has wrong ELF machine");
}
let header_size = match parsed.ehdr.class {
elf::file::Class::ELF32 => 0x34,
elf::file::Class::ELF64 => 0x40,
};
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())
},
]
}
}