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::ptr::null_mut;
|
||||||
use core::ffi::c_void;
|
use core::ffi::c_void;
|
||||||
|
|
||||||
pub const OPEN_MODE_READ: u64 = 1;
|
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)]
|
#[repr(C)]
|
||||||
pub struct FileProtocol {
|
pub struct FileProtocol {
|
||||||
@@ -17,6 +23,17 @@ pub struct FileProtocol {
|
|||||||
write: *mut c_void,
|
write: *mut c_void,
|
||||||
get_position: *mut c_void,
|
get_position: *mut c_void,
|
||||||
set_position: unsafe fn (*mut FileProtocol, u64) -> u64,
|
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 {
|
pub struct File {
|
||||||
@@ -81,4 +98,19 @@ impl File {
|
|||||||
)
|
)
|
||||||
}).into()
|
}).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
|
dd if=/dev/zero of=${IMAGE} bs=1M count=64
|
||||||
mkfs.vfat -F32 ${IMAGE}
|
mkfs.vfat -F32 ${IMAGE}
|
||||||
mcopy -i ${IMAGE} target/${TARGET}/${CONFIG}/yboot2.efi ::app.efi
|
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
|
mcopy -i ${IMAGE} image/kernel.elf ::kernel.elf
|
||||||
|
|
||||||
qemu-system-x86_64 \
|
qemu-system-x86_64 \
|
||||||
|
|||||||
+19
-6
@@ -50,18 +50,21 @@ struct Shdr {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Phdr {
|
struct Phdr {
|
||||||
_type: Word,
|
_type: Word,
|
||||||
|
flags: Word,
|
||||||
offset: Off,
|
offset: Off,
|
||||||
vaddr: Addr,
|
vaddr: Addr,
|
||||||
paddr: Addr,
|
paddr: Addr,
|
||||||
filesz: Word,
|
filesz: XWord,
|
||||||
memsz: Word,
|
memsz: XWord,
|
||||||
flags: Word,
|
align: XWord
|
||||||
align: Word
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
file: File,
|
file: File,
|
||||||
ehdr: Ehdr,
|
ehdr: Ehdr,
|
||||||
|
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn any_as_u8_slice<T: Sized>(p: &mut T) -> &mut [u8] {
|
unsafe fn any_as_u8_slice<T: Sized>(p: &mut T) -> &mut [u8] {
|
||||||
@@ -77,6 +80,8 @@ impl Object {
|
|||||||
let mut obj = Object {
|
let mut obj = Object {
|
||||||
file: root.open(path, efi::proto::fp::OPEN_MODE_READ, 0)?,
|
file: root.open(path, efi::proto::fp::OPEN_MODE_READ, 0)?,
|
||||||
ehdr: unsafe { MaybeUninit::uninit().assume_init() },
|
ehdr: unsafe { MaybeUninit::uninit().assume_init() },
|
||||||
|
start: 0xFFFFFFFFFFFFFFFF,
|
||||||
|
end: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load header
|
// Load header
|
||||||
@@ -148,6 +153,7 @@ impl Object {
|
|||||||
let mut phdr = unsafe { MaybeUninit::<Phdr>::uninit().assume_init() };
|
let mut phdr = unsafe { MaybeUninit::<Phdr>::uninit().assume_init() };
|
||||||
|
|
||||||
// 1. Check that all pages in load segments are usable
|
// 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 {
|
for i in 0 .. self.ehdr.phnum {
|
||||||
self.read_phdr(&mut phdr, i as usize)?;
|
self.read_phdr(&mut phdr, i as usize)?;
|
||||||
|
|
||||||
@@ -155,6 +161,13 @@ impl Object {
|
|||||||
let start = phdr.paddr & !0xFFF;
|
let start = phdr.paddr & !0xFFF;
|
||||||
let end = (phdr.paddr + phdr.memsz as u64 + 0xFFF) & !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) {
|
for addr in (start .. end).step_by(0x1000) {
|
||||||
if !mmap.is_usable_now(addr as usize) {
|
if !mmap.is_usable_now(addr as usize) {
|
||||||
return Err(Status::InvalidParameter);
|
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]
|
#[macro_use]
|
||||||
mod println;
|
mod println;
|
||||||
|
mod initrd;
|
||||||
mod proto;
|
mod proto;
|
||||||
mod elf;
|
mod elf;
|
||||||
|
|
||||||
@@ -39,11 +40,17 @@ fn main() -> efi::Result<()> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut root = image_handle().get_boot_path()?.open_partition()?;
|
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 mut obj = elf::Object::open(&mut root, CStr16::from_literal(cstr16!(r"\kernel.elf")))?;
|
||||||
let entry = obj.load(&mmap)?;
|
let entry = obj.load(&mmap)?;
|
||||||
let data = obj.locate_protocol_data::<proto::V1>()?;
|
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
|
// Get the new memory map and terminate boot services
|
||||||
bs.get_memory_map(&mut mmap)?;
|
bs.get_memory_map(&mut mmap)?;
|
||||||
@@ -51,7 +58,7 @@ fn main() -> efi::Result<()> {
|
|||||||
|
|
||||||
use proto::LoadProtocol;
|
use proto::LoadProtocol;
|
||||||
data.set_mmap(&mmap);
|
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_acpi_rsdp(rsdp as usize);
|
||||||
data.set_loader_magic();
|
data.set_loader_magic();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user