Move load protocol impl outside
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)?;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user