diff --git a/.cargo/config b/.cargo/config index e2dee73..3dfc27d 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,8 @@ [build] target = "x86_64-unknown-uefi" +[unstable] +build-std = ["core"] + [target.x86_64-unknown-uefi] rustflags = ["-Ccode-model=small", "-Clink-arg=/debug:none"] diff --git a/Cargo.lock b/Cargo.lock index a4e3c81..067ed35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,4 +25,4 @@ dependencies = [ [[package]] name = "yboot2-proto" version = "0.1.0" -source = "git+https://git.alnyan.me/yggdrasil/yboot2-proto.git#fa586d7d0d7664826e344e830554486ba9cec933" +source = "git+https://git.alnyan.me/yggdrasil/yboot2-proto.git#e125ef89d686e6fc1f539d643b24cf54e5f96ea9" diff --git a/Cargo.toml b/Cargo.toml index bfd5383..245c71b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,7 @@ edition = "2018" efi = { path = "crates/efi" } char16-literal = { path = "crates/char16-literal" } core-rt = { path = "crates/core-rt" } -yboot2-proto = { git = "https://git.alnyan.me/yggdrasil/yboot2-proto.git" } + +[dependencies.yboot2-proto] +git = "https://git.alnyan.me/yggdrasil/yboot2-proto.git" +features = ["kernel-protocol", "load-protocol"] diff --git a/src/elf.rs b/src/elf.rs index 6f998ea..db759b1 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -1,6 +1,6 @@ use efi::{File, Status, CStr16, MemoryMap}; use core::mem::{MaybeUninit, size_of}; -use yboot2_proto::LoadProtocol; +use yboot2_proto::{LoadProtocol, KernelProtocol}; type Off = u64; type Addr = u64; @@ -121,7 +121,7 @@ impl Object { } // Called after load() - pub fn locate_protocol_data(&mut self) + pub fn locate_protocol_data(&mut self) -> Result<&'static mut T, Status> { let mut shdr = unsafe { MaybeUninit::::uninit().assume_init() }; diff --git a/src/main.rs b/src/main.rs index 2584502..45120e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,15 +17,26 @@ use efi::{ system_table, image_handle, }; -use yboot2_proto::LoadProtocol; +use yboot2_proto::{LoadProtocol, ProtoV1, MemoryMapInfo}; +use core::convert::TryInto; #[macro_use] mod println; mod initrd; -mod proto; mod video; mod elf; +fn set_efi_mmap(data: &mut T, mmap: &efi::MemoryMap) -> efi::Result<()> { + match data.set_mmap(&MemoryMapInfo { + address: mmap.storage_ref.as_ptr() as u64, + entsize: mmap.descriptor_size.try_into().unwrap(), + size: mmap.size.try_into().unwrap() + }) { + Err(_) => Err(Status::Err), + Ok(()) => Ok(()) + } +} + fn main() -> efi::Result<()> { let mut desc_array = [0u8; 16384]; let mut mmap = efi::MemoryMap::new(&mut desc_array); @@ -48,22 +59,27 @@ fn main() -> efi::Result<()> { // 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::()?; + let data = obj.locate_protocol_data::()?; - // Load initrd - let (initrd_base, initrd_size) = initrd::load_somewhere(&mut root, - CStr16::from_literal(cstr16!(r"\initrd.img")), - &mmap, - &obj)?; + if (data.get_flags() & yboot2_proto::FLAG_INITRD) != 0 { + // Load initrd + let (initrd_base, initrd_size) = initrd::load_somewhere(&mut root, + CStr16::from_literal(cstr16!(r"\initrd.img")), + &mmap, + &obj)?; + + // Set video mode + data.set_initrd(initrd_base, initrd_size); + } else { + data.set_initrd(0, 0); + } - // Set video mode - data.set_initrd(initrd_base, initrd_size); data.set_acpi_rsdp(rsdp.unwrap_or(core::ptr::null_mut()) as usize); data.set_loader_magic(); // Get the new memory map and terminate boot services bs.get_memory_map(&mut mmap)?; - data.set_efi_mmap(&mmap); + set_efi_mmap(data, &mmap)?; video::set_mode(bs, data)?; bs.exit_boot_services(mmap.key)?; diff --git a/src/proto.rs b/src/proto.rs deleted file mode 100644 index a87601c..0000000 --- a/src/proto.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::convert::TryInto; -use yboot2_proto::{ - ProtoV1, - LoadProtocol, - PixelFormat, - MemoryMapInfo, - VideoInfo, - VideoRequest -}; - -pub struct V1 { - proto: ProtoV1 -} - -impl LoadProtocol for V1 { - const KERNEL_MAGIC: [u8; 8] = [ - 0x07, 0xB0, 0x07, 0xB0, 0xA9, 0x97, 0xA1, 0x00 - ]; - - fn set_loader_magic(&mut self) { - const LOADER_MAGIC: [u8; 8] = [ - 0x1A, 0x79, 0x9A, 0x0B, 0x70, 0x0B, 0x70, 0x00 - ]; - self.proto.hdr.loader_magic = LOADER_MAGIC; - } - - fn set_mmap(&mut self, map: &MemoryMapInfo) { - let ptr = map.address as *const u8; - if ptr >= 0x100000000 as *const _ { - panic!("Memory map pointer crosses 4GiB"); - } - if map.size > self.proto.memory_map_size { - panic!("Can't fit memory map"); - } - - unsafe { - extern "C" { - fn memcpy(dst: *mut u8, src: *const u8, count: usize) -> *mut u8; - } - memcpy(self.proto.memory_map_data as *mut _, ptr, map.size as usize); - } - - self.proto.memory_map_size = map.size; - self.proto.memory_map_entsize = map.entsize; - } - - fn set_initrd(&mut self, base: usize, size: usize) { - if self.proto.initrd_base + self.proto.initrd_size >= 0x100000000 { - panic!("Initrd crosses 4GiB"); - } - self.proto.initrd_base = base.try_into().unwrap(); - self.proto.initrd_size = size.try_into().unwrap(); - } - - fn set_acpi_rsdp(&mut self, rsdp: usize) { - self.proto.rsdp = rsdp.try_into().unwrap(); - } - - fn get_video_request(&self) -> VideoRequest { - use core::convert::TryFrom; - VideoRequest { - width: self.proto.video_width, - height: self.proto.video_height, - format: PixelFormat::try_from(self.proto.video_format).unwrap() - } - } - - fn set_video_info(&mut self, info: &VideoInfo) { - if info.framebuffer >= 0x100000000 { - panic!("Video framebuffer address is above 4GiB"); - } - - self.proto.video_width = info.width; - self.proto.video_height = info.height; - self.proto.video_format = info.format as u32; - self.proto.video_framebuffer = info.framebuffer as u64; - self.proto.video_pitch = info.pitch as u64; - } -} - -impl V1 { - pub fn set_efi_mmap(&mut self, mmap: &efi::MemoryMap) { - self.set_mmap(&MemoryMapInfo { - address: mmap.storage_ref.as_ptr() as u64, - entsize: mmap.descriptor_size.try_into().unwrap(), - size: mmap.size.try_into().unwrap() - }); - } -} diff --git a/src/video.rs b/src/video.rs index 9130290..b592625 100644 --- a/src/video.rs +++ b/src/video.rs @@ -1,4 +1,4 @@ -use yboot2_proto::{LoadProtocol, VideoRequest, VideoInfo, PixelFormat}; +use yboot2_proto::{LoadProtocol, VideoInfo, video::PixelFormat}; use efi::{BootServices, Status, GraphicsOutputProtocol, gop::ModeInformation}; // TODO: "Any" format @@ -18,12 +18,11 @@ fn pixel_from_efi(from: efi::gop::PixelFormat) -> Option { match from { PixelRedGreenBlueReserved8BitPerColor => Some(PixelFormat::LfbRgb32), PixelBlueGreenRedReserved8BitPerColor => Some(PixelFormat::LfbBgr32), - _ => None } } fn find_mode(proto: &GraphicsOutputProtocol, - req: &VideoRequest) -> Result<(u32, &'static ModeInformation), Status> { + req: &VideoInfo) -> Result<(u32, &'static ModeInformation), Status> { let req_format = pixel_to_efi(req.format).unwrap(); for (num, info) in proto.mode_iter() { if info.horizontal_resolution == req.width && @@ -36,10 +35,9 @@ fn find_mode(proto: &GraphicsOutputProtocol, } pub fn set_mode(bs: &BootServices, data: &mut T) -> Result<(), Status> { - let req = data.get_video_request(); let gop = bs.locate_protocol::()?; - match find_mode(gop, &req) { + match find_mode(gop, data.get_video_info()) { Ok((num, info)) => { let mode = gop.set_mode(num)?; @@ -47,8 +45,8 @@ pub fn set_mode(bs: &BootServices, data: &mut T) -> Result<(), width: info.horizontal_resolution, height: info.vertical_resolution, format: pixel_from_efi(info.pixel_format).unwrap(), - framebuffer: mode.framebuffer_addr(), - pitch: 4 * info.horizontal_resolution as usize + framebuffer: mode.framebuffer_addr() as u64, + pitch: 4 * info.horizontal_resolution as u64 }; data.set_video_info(&info);