Add initrd loading

This commit is contained in:
Mark
2020-09-17 15:27:01 +03:00
parent f590caff1c
commit 8f601b7255
5 changed files with 114 additions and 10 deletions
+33 -1
View File
@@ -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)
}
}
}
+1 -1
View File
@@ -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
View File
@@ -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);
+52
View File
@@ -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
View File
@@ -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();