Add initrd loading
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
use crate::{CStr16, Status};
|
||||
use crate::{CStr16, Status, Guid};
|
||||
use core::ptr::null_mut;
|
||||
use core::ffi::c_void;
|
||||
|
||||
pub const OPEN_MODE_READ: u64 = 1;
|
||||
pub const FILE_INFO_GUID: Guid = Guid {
|
||||
data1: 0x09576e92,
|
||||
data2: 0x6d3f,
|
||||
data3: 0x11d2,
|
||||
data4: [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FileProtocol {
|
||||
@@ -17,6 +23,17 @@ pub struct FileProtocol {
|
||||
write: *mut c_void,
|
||||
get_position: *mut c_void,
|
||||
set_position: unsafe fn (*mut FileProtocol, u64) -> u64,
|
||||
get_info: unsafe fn (*mut FileProtocol,
|
||||
*const Guid,
|
||||
*mut usize,
|
||||
*mut c_void) -> u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Stat {
|
||||
pub size: u64,
|
||||
pub file_size: u64,
|
||||
// ...
|
||||
}
|
||||
|
||||
pub struct File {
|
||||
@@ -81,4 +98,19 @@ impl File {
|
||||
)
|
||||
}).into()
|
||||
}
|
||||
|
||||
pub fn stat(&mut self, statbuf: &mut [u8]) -> Result<&Stat, Status> {
|
||||
let mut len = statbuf.len();
|
||||
match Status::from(unsafe {
|
||||
((*self.inner).get_info)(
|
||||
self.inner,
|
||||
&FILE_INFO_GUID,
|
||||
&mut len,
|
||||
statbuf.as_mut_ptr() as *mut _
|
||||
)
|
||||
}) {
|
||||
Status::Success => Ok(unsafe {core::mem::transmute(statbuf.as_ptr())}),
|
||||
err => Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ cargo build -Z build-std=core
|
||||
dd if=/dev/zero of=${IMAGE} bs=1M count=64
|
||||
mkfs.vfat -F32 ${IMAGE}
|
||||
mcopy -i ${IMAGE} target/${TARGET}/${CONFIG}/yboot2.efi ::app.efi
|
||||
mcopy -i ${IMAGE} image/config.txt ::config.txt
|
||||
mcopy -i ${IMAGE} image/initrd.img ::initrd.img
|
||||
mcopy -i ${IMAGE} image/kernel.elf ::kernel.elf
|
||||
|
||||
qemu-system-x86_64 \
|
||||
|
||||
+19
-6
@@ -50,18 +50,21 @@ struct Shdr {
|
||||
#[repr(C)]
|
||||
struct Phdr {
|
||||
_type: Word,
|
||||
flags: Word,
|
||||
offset: Off,
|
||||
vaddr: Addr,
|
||||
paddr: Addr,
|
||||
filesz: Word,
|
||||
memsz: Word,
|
||||
flags: Word,
|
||||
align: Word
|
||||
filesz: XWord,
|
||||
memsz: XWord,
|
||||
align: XWord
|
||||
}
|
||||
|
||||
pub struct Object {
|
||||
file: File,
|
||||
ehdr: Ehdr,
|
||||
file: File,
|
||||
ehdr: Ehdr,
|
||||
|
||||
pub start: usize,
|
||||
pub end: usize
|
||||
}
|
||||
|
||||
unsafe fn any_as_u8_slice<T: Sized>(p: &mut T) -> &mut [u8] {
|
||||
@@ -77,6 +80,8 @@ impl Object {
|
||||
let mut obj = Object {
|
||||
file: root.open(path, efi::proto::fp::OPEN_MODE_READ, 0)?,
|
||||
ehdr: unsafe { MaybeUninit::uninit().assume_init() },
|
||||
start: 0xFFFFFFFFFFFFFFFF,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
// Load header
|
||||
@@ -148,6 +153,7 @@ impl Object {
|
||||
let mut phdr = unsafe { MaybeUninit::<Phdr>::uninit().assume_init() };
|
||||
|
||||
// 1. Check that all pages in load segments are usable
|
||||
// Also find out kernel's lowest and highest physical addresses
|
||||
for i in 0 .. self.ehdr.phnum {
|
||||
self.read_phdr(&mut phdr, i as usize)?;
|
||||
|
||||
@@ -155,6 +161,13 @@ impl Object {
|
||||
let start = phdr.paddr & !0xFFF;
|
||||
let end = (phdr.paddr + phdr.memsz as u64 + 0xFFF) & !0xFFF;
|
||||
|
||||
if (start as usize) < self.start {
|
||||
self.start = start as usize;
|
||||
}
|
||||
if (end as usize) > self.end {
|
||||
self.end = end as usize;
|
||||
}
|
||||
|
||||
for addr in (start .. end).step_by(0x1000) {
|
||||
if !mmap.is_usable_now(addr as usize) {
|
||||
return Err(Status::InvalidParameter);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use efi::{File, CStr16, Status};
|
||||
use core::mem::MaybeUninit;
|
||||
use crate::elf;
|
||||
|
||||
fn check_placement(mmap: &efi::MemoryMap, base: usize, size: usize) -> bool {
|
||||
for page in (base & !0xFFF .. (base + size + 0xFFF) & !0xFFF).step_by(0x1000) {
|
||||
if !mmap.is_usable_now(page) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn do_load(file: &mut File, base: usize, size: usize) -> efi::Result<()> {
|
||||
file.read(unsafe {core::slice::from_raw_parts_mut(base as *mut u8, size)})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_somewhere(root: &mut File,
|
||||
filename: &CStr16,
|
||||
mmap: &efi::MemoryMap,
|
||||
obj: &elf::Object) -> efi::Result<(usize, usize)> {
|
||||
let mut statbuf: [u8; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
let mut file = root.open(filename,
|
||||
efi::proto::fp::OPEN_MODE_READ,
|
||||
0)?;
|
||||
let stat = file.stat(&mut statbuf)?;
|
||||
let size = stat.file_size as usize;
|
||||
|
||||
// 1. Try loading right below the kernel
|
||||
if obj.start >= size {
|
||||
let start = (obj.start - size) & !0xFFF;
|
||||
|
||||
if check_placement(mmap, start, size) {
|
||||
println!("Loading initrd below the kernel at 0x{:016x}", start);
|
||||
do_load(&mut file, start, size)?;
|
||||
return Ok((start, size));
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Any location above the kernel
|
||||
for start in ((obj.end + 0x3FFF) & !0xFFF .. 0x100000000).step_by(0x1000) {
|
||||
if check_placement(mmap, start, size) {
|
||||
println!("Loading initrd at 0x{:016x}", start);
|
||||
do_load(&mut file, start, size)?;
|
||||
return Ok((start, size));
|
||||
}
|
||||
}
|
||||
|
||||
Err(Status::InvalidParameter)
|
||||
}
|
||||
|
||||
+9
-2
@@ -19,6 +19,7 @@ use efi::{
|
||||
|
||||
#[macro_use]
|
||||
mod println;
|
||||
mod initrd;
|
||||
mod proto;
|
||||
mod elf;
|
||||
|
||||
@@ -39,11 +40,17 @@ fn main() -> efi::Result<()> {
|
||||
.unwrap();
|
||||
|
||||
let mut root = image_handle().get_boot_path()?.open_partition()?;
|
||||
|
||||
// Load kernel
|
||||
let mut obj = elf::Object::open(&mut root, CStr16::from_literal(cstr16!(r"\kernel.elf")))?;
|
||||
let entry = obj.load(&mmap)?;
|
||||
let data = obj.locate_protocol_data::<proto::V1>()?;
|
||||
|
||||
// TODO: load initrd
|
||||
// Load initrd
|
||||
let (initrd_base, initrd_size) = initrd::load_somewhere(&mut root,
|
||||
CStr16::from_literal(cstr16!(r"\initrd.img")),
|
||||
&mmap,
|
||||
&obj)?;
|
||||
|
||||
// Get the new memory map and terminate boot services
|
||||
bs.get_memory_map(&mut mmap)?;
|
||||
@@ -51,7 +58,7 @@ fn main() -> efi::Result<()> {
|
||||
|
||||
use proto::LoadProtocol;
|
||||
data.set_mmap(&mmap);
|
||||
data.set_initrd(0, 0);
|
||||
data.set_initrd(initrd_base, initrd_size);
|
||||
data.set_acpi_rsdp(rsdp as usize);
|
||||
data.set_loader_magic();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user