Move load protocol impl outside

This commit is contained in:
Mark
2020-09-21 13:48:58 +03:00
parent 6b846b513a
commit e87f46382c
7 changed files with 42 additions and 111 deletions
+3
View File
@@ -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"]
Generated
+1 -1
View File
@@ -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"
+4 -1
View File
@@ -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"]
+2 -2
View File
@@ -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<T: LoadProtocol>(&mut self)
pub fn locate_protocol_data<T: KernelProtocol + LoadProtocol>(&mut self)
-> Result<&'static mut T, Status>
{
let mut shdr = unsafe { MaybeUninit::<Shdr>::uninit().assume_init() };
+27 -11
View File
@@ -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<T: LoadProtocol>(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::<proto::V1>()?;
let data = obj.locate_protocol_data::<ProtoV1>()?;
// 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)?;
-89
View File
@@ -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()
});
}
}
+5 -7
View File
@@ -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<PixelFormat> {
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<T: LoadProtocol>(bs: &BootServices, data: &mut T) -> Result<(), Status> {
let req = data.get_video_request();
let gop = bs.locate_protocol::<GraphicsOutputProtocol>()?;
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<T: LoadProtocol>(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);