More detailed error reporting
This commit is contained in:
parent
f362616fdc
commit
448e9c7abe
186
src/elf.rs
186
src/elf.rs
@ -1,6 +1,7 @@
|
||||
use efi::{File, Status, CStr16, MemoryMap};
|
||||
use core::mem::{MaybeUninit, size_of};
|
||||
use yboot2_proto::{Magic, LoadProtocol};
|
||||
use crate::error::{ImageLoadError, ProtocolError};
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use efi::{CStr16, File, MemoryMap, Status};
|
||||
use yboot2_proto::{LoadProtocol, Magic};
|
||||
|
||||
type Off = u64;
|
||||
type Addr = u64;
|
||||
@ -17,136 +18,148 @@ const SHF_ALLOC: XWord = 1 << 1;
|
||||
|
||||
#[repr(C)]
|
||||
struct Ehdr {
|
||||
ident: [u8; 16],
|
||||
_type: Half,
|
||||
machine: Half,
|
||||
version: Word,
|
||||
entry: Addr,
|
||||
phoff: Off,
|
||||
shoff: Off,
|
||||
flags: Word,
|
||||
ehsize: Half,
|
||||
phentsize: Half,
|
||||
phnum: Half,
|
||||
shentsize: Half,
|
||||
shnum: Half,
|
||||
shstrndx: Half
|
||||
ident: [u8; 16],
|
||||
_type: Half,
|
||||
machine: Half,
|
||||
version: Word,
|
||||
entry: Addr,
|
||||
phoff: Off,
|
||||
shoff: Off,
|
||||
flags: Word,
|
||||
ehsize: Half,
|
||||
phentsize: Half,
|
||||
phnum: Half,
|
||||
shentsize: Half,
|
||||
shnum: Half,
|
||||
shstrndx: Half,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Shdr {
|
||||
name: Word,
|
||||
_type: Word,
|
||||
flags: XWord,
|
||||
addr: Addr,
|
||||
offset: Off,
|
||||
size: XWord,
|
||||
link: Word,
|
||||
info: Word,
|
||||
addralign: XWord,
|
||||
entsize: XWord
|
||||
name: Word,
|
||||
_type: Word,
|
||||
flags: XWord,
|
||||
addr: Addr,
|
||||
offset: Off,
|
||||
size: XWord,
|
||||
link: Word,
|
||||
info: Word,
|
||||
addralign: XWord,
|
||||
entsize: XWord,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Phdr {
|
||||
_type: Word,
|
||||
flags: Word,
|
||||
offset: Off,
|
||||
vaddr: Addr,
|
||||
paddr: Addr,
|
||||
filesz: XWord,
|
||||
memsz: XWord,
|
||||
align: XWord
|
||||
_type: Word,
|
||||
flags: Word,
|
||||
offset: Off,
|
||||
vaddr: Addr,
|
||||
paddr: Addr,
|
||||
filesz: XWord,
|
||||
memsz: XWord,
|
||||
align: XWord,
|
||||
}
|
||||
|
||||
pub struct Object {
|
||||
file: File,
|
||||
ehdr: Ehdr,
|
||||
file: File,
|
||||
ehdr: Ehdr,
|
||||
|
||||
pub start: usize,
|
||||
pub end: usize
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
unsafe fn any_as_u8_slice<T: Sized>(p: &mut T) -> &mut [u8] {
|
||||
::core::slice::from_raw_parts_mut(
|
||||
(p as *mut T) as *mut u8,
|
||||
::core::mem::size_of::<T>(),
|
||||
)
|
||||
::core::slice::from_raw_parts_mut((p as *mut T) as *mut u8, ::core::mem::size_of::<T>())
|
||||
}
|
||||
|
||||
impl Object {
|
||||
// Reason: EFI autism
|
||||
pub fn open(root: &mut File, path: &CStr16) -> Result<Object, Status> {
|
||||
pub fn open(root: &mut File, path: &CStr16) -> Result<Object, ImageLoadError> {
|
||||
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)
|
||||
.map_err(ImageLoadError::IOError)?,
|
||||
ehdr: unsafe { MaybeUninit::uninit().assume_init() },
|
||||
start: 0xFFFFFFFFFFFFFFFF,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
// Load header
|
||||
obj.file.seek(0)?;
|
||||
obj.file.read(unsafe {any_as_u8_slice(&mut obj.ehdr)})?;
|
||||
obj.file.seek(0).map_err(ImageLoadError::IOError)?;
|
||||
obj.file
|
||||
.read(unsafe { any_as_u8_slice(&mut obj.ehdr) })
|
||||
.map_err(ImageLoadError::IOError)?;
|
||||
|
||||
// Validate that this is ELF
|
||||
if &obj.ehdr.ident[0 .. 4] != [0x7F, b'E', b'L', b'F'] {
|
||||
return Err(Status::InvalidParameter);
|
||||
if &obj.ehdr.ident[0..4] != [0x7F, b'E', b'L', b'F'] {
|
||||
return Err(ImageLoadError::BadMagic);
|
||||
}
|
||||
|
||||
// Validate that bitness matches requested
|
||||
if obj.ehdr.ident[4] != 2 {
|
||||
return Err(Status::InvalidParameter);
|
||||
return Err(ImageLoadError::BadTarget);
|
||||
}
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
fn read_phdr(&mut self, phdr: &mut Phdr, index: usize) -> Result<(), Status> {
|
||||
fn read_phdr(&mut self, phdr: &mut Phdr, index: usize) -> Result<(), ImageLoadError> {
|
||||
let off = self.ehdr.phoff + self.ehdr.phentsize as u64 * index as u64;
|
||||
self.file.seek(off)?;
|
||||
if self.file.read(unsafe { any_as_u8_slice(phdr) })? != size_of::<Phdr>() {
|
||||
Err(Status::Err)
|
||||
self.file.seek(off).map_err(ImageLoadError::IOError)?;
|
||||
if self
|
||||
.file
|
||||
.read(unsafe { any_as_u8_slice(phdr) })
|
||||
.map_err(ImageLoadError::IOError)?
|
||||
!= size_of::<Phdr>()
|
||||
{
|
||||
Err(ImageLoadError::IOError(efi::Status::Err))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn read_shdr(&mut self, shdr: &mut Shdr, index: usize) -> Result<(), Status> {
|
||||
fn read_shdr(&mut self, shdr: &mut Shdr, index: usize) -> Result<(), ImageLoadError> {
|
||||
let off = self.ehdr.shoff + self.ehdr.shentsize as u64 * index as u64;
|
||||
self.file.seek(off)?;
|
||||
if self.file.read(unsafe { any_as_u8_slice(shdr) })? != size_of::<Shdr>() {
|
||||
Err(Status::Err)
|
||||
self.file.seek(off).map_err(ImageLoadError::IOError)?;
|
||||
if self
|
||||
.file
|
||||
.read(unsafe { any_as_u8_slice(shdr) })
|
||||
.map_err(ImageLoadError::IOError)?
|
||||
!= size_of::<Shdr>()
|
||||
{
|
||||
Err(ImageLoadError::IOError(efi::Status::Err))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Called after load()
|
||||
pub fn locate_protocol_data<T: Magic + LoadProtocol>(&mut self)
|
||||
-> Result<&'static mut T, Status>
|
||||
{
|
||||
pub fn locate_protocol_data<T: Magic + LoadProtocol>(
|
||||
&mut self,
|
||||
) -> Result<&'static mut T, ImageLoadError> {
|
||||
let mut shdr = unsafe { MaybeUninit::<Shdr>::uninit().assume_init() };
|
||||
|
||||
for i in 0 .. self.ehdr.shnum {
|
||||
for i in 0..self.ehdr.shnum {
|
||||
self.read_shdr(&mut shdr, i as usize)?;
|
||||
|
||||
if shdr._type == SHT_PROGBITS &&
|
||||
(shdr.flags & (SHF_ALLOC | SHF_WRITE)) == SHF_ALLOC | SHF_WRITE {
|
||||
if shdr._type == SHT_PROGBITS
|
||||
&& (shdr.flags & (SHF_ALLOC | SHF_WRITE)) == SHF_ALLOC | SHF_WRITE
|
||||
{
|
||||
if shdr.size as usize >= size_of::<T>() {
|
||||
// Make a physical address
|
||||
let ptr = shdr.addr - 0xFFFFFF0000000000;
|
||||
let magic: &[u8] = unsafe { core::slice::from_raw_parts(ptr as *const _, 8)};
|
||||
let magic: &[u8] = unsafe { core::slice::from_raw_parts(ptr as *const _, 8) };
|
||||
if magic == T::KERNEL_MAGIC {
|
||||
return Ok(unsafe { &mut *(ptr as *mut _) })
|
||||
return Ok(unsafe { &mut *(ptr as *mut _) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Status::InvalidParameter)
|
||||
Err(ImageLoadError::NoProtocol)
|
||||
}
|
||||
|
||||
pub fn load(&mut self, mmap: &MemoryMap) -> Result<usize, Status> {
|
||||
extern {
|
||||
pub fn load(&mut self, mmap: &MemoryMap) -> Result<usize, ImageLoadError> {
|
||||
extern "C" {
|
||||
fn memset(block: *mut u8, value: i32, count: usize) -> *mut u8;
|
||||
}
|
||||
|
||||
@ -154,10 +167,18 @@ impl Object {
|
||||
|
||||
// 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)?;
|
||||
|
||||
if phdr._type == PT_LOAD {
|
||||
if phdr.paddr + phdr.memsz >= 0x100000000 {
|
||||
return Err(ImageLoadError::BadAddress(
|
||||
phdr.paddr + phdr.memsz,
|
||||
0,
|
||||
0x100000000,
|
||||
));
|
||||
}
|
||||
|
||||
let start = phdr.paddr & !0xFFF;
|
||||
let end = (phdr.paddr + phdr.memsz as u64 + 0xFFF) & !0xFFF;
|
||||
|
||||
@ -168,36 +189,37 @@ impl Object {
|
||||
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) {
|
||||
return Err(Status::InvalidParameter);
|
||||
return Err(ImageLoadError::BadSegment(start, end, addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Load segments
|
||||
for i in 0 .. self.ehdr.phnum {
|
||||
for i in 0..self.ehdr.phnum {
|
||||
self.read_phdr(&mut phdr, i as usize)?;
|
||||
|
||||
if phdr._type == PT_LOAD {
|
||||
// Load what's provided in ELF
|
||||
if phdr.filesz > 0 {
|
||||
let mut data = unsafe {core::slice::from_raw_parts_mut(
|
||||
phdr.paddr as *mut u8,
|
||||
phdr.filesz as usize,
|
||||
)};
|
||||
let mut data = unsafe {
|
||||
core::slice::from_raw_parts_mut(phdr.paddr as *mut u8, phdr.filesz as usize)
|
||||
};
|
||||
|
||||
self.file.seek(phdr.offset)?;
|
||||
self.file.read(&mut data)?;
|
||||
self.file.seek(phdr.offset).map_err(ImageLoadError::IOError)?;
|
||||
self.file.read(&mut data).map_err(ImageLoadError::IOError)?;
|
||||
}
|
||||
|
||||
// Zero the rest
|
||||
if phdr.memsz > phdr.filesz {
|
||||
unsafe {
|
||||
memset((phdr.paddr as usize + phdr.filesz as usize) as *mut u8,
|
||||
0,
|
||||
(phdr.memsz - phdr.filesz) as usize);
|
||||
memset(
|
||||
(phdr.paddr as usize + phdr.filesz as usize) as *mut u8,
|
||||
0,
|
||||
(phdr.memsz - phdr.filesz) as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
104
src/error.rs
Normal file
104
src/error.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use core::fmt;
|
||||
|
||||
use efi;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BootError {
|
||||
ImageLoadError(ImageLoadError),
|
||||
InitrdLoadError(InitrdLoadError),
|
||||
ProtocolError(ProtocolError),
|
||||
MemoryMapError(efi::Status),
|
||||
FileError(efi::Status),
|
||||
TerminateServicesError(efi::Status),
|
||||
VideoModeUnsupported,
|
||||
VideoModeFailed,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ImageLoadError {
|
||||
BadAddress(u64, u64, u64),
|
||||
BadSegment(u64, u64, u64),
|
||||
IOError(efi::Status),
|
||||
NoProtocol,
|
||||
BadMagic,
|
||||
BadTarget,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InitrdLoadError {
|
||||
IOError(efi::Status),
|
||||
NoSpace,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProtocolError {}
|
||||
|
||||
impl From<ProtocolError> for BootError {
|
||||
fn from(p: ProtocolError) -> Self {
|
||||
BootError::ProtocolError(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitrdLoadError> for BootError {
|
||||
fn from(p: InitrdLoadError) -> Self {
|
||||
BootError::InitrdLoadError(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageLoadError> for BootError {
|
||||
fn from(p: ImageLoadError) -> Self {
|
||||
BootError::ImageLoadError(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BootError> for efi::Status {
|
||||
fn from(f: &BootError) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BootError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use BootError::*;
|
||||
match self {
|
||||
ImageLoadError(e) => e.fmt(f),
|
||||
InitrdLoadError(e) => e.fmt(f),
|
||||
_ => {
|
||||
write!(f, "Unknown error: {:?}", self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InitrdLoadError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use InitrdLoadError::*;
|
||||
match self {
|
||||
IOError(e) => write!(f, "I/O or file error (initrd): {:?}", e),
|
||||
NoSpace => write!(f, "Failed to fit initrd in memory"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ImageLoadError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use ImageLoadError::*;
|
||||
match self {
|
||||
BadAddress(addr, start, end) => write!(
|
||||
f,
|
||||
"Invalid image address: 0x{:016x}. Expected in range 0x{:016x} .. 0x{:016x}",
|
||||
addr, start, end
|
||||
),
|
||||
BadSegment(page, start, end) => write!(
|
||||
f,
|
||||
"Invalid segment range: 0x{:016x} .. 0x{:016x}. Page 0x{:016x} can't be used.",
|
||||
start, end, page
|
||||
),
|
||||
IOError(e) => write!(f, "I/O or file error (image): {:?}", e),
|
||||
NoProtocol => write!(f, "The image doesn't have a protocol structure"),
|
||||
BadTarget => write!(f, "The image targets a different arch"),
|
||||
BadMagic => write!(f, "Bad image magic"),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
use efi::{File, CStr16, Status};
|
||||
use core::mem::MaybeUninit;
|
||||
use crate::elf;
|
||||
use crate::error::InitrdLoadError;
|
||||
use core::mem::MaybeUninit;
|
||||
use efi::{CStr16, File, Status};
|
||||
|
||||
fn check_placement(mmap: &efi::MemoryMap, base: usize, size: usize) -> bool {
|
||||
for page in (base & !0xFFF .. (base + size + 0xFFF) & !0xFFF).step_by(0x1000) {
|
||||
for page in (base & !0xFFF..(base + size + 0xFFF) & !0xFFF).step_by(0x1000) {
|
||||
if !mmap.is_usable_now(page) {
|
||||
return false;
|
||||
}
|
||||
@ -11,20 +12,23 @@ fn check_placement(mmap: &efi::MemoryMap, base: usize, size: usize) -> bool {
|
||||
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)})?;
|
||||
fn do_load(file: &mut File, base: usize, size: usize) -> Result<(), InitrdLoadError> {
|
||||
file.read(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, size) })
|
||||
.map_err(InitrdLoadError::IOError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_somewhere(root: &mut File,
|
||||
filename: &CStr16,
|
||||
mmap: &efi::MemoryMap,
|
||||
obj: &elf::Object) -> efi::Result<(usize, usize)> {
|
||||
pub fn load_somewhere(
|
||||
root: &mut File,
|
||||
filename: &CStr16,
|
||||
mmap: &efi::MemoryMap,
|
||||
obj: &elf::Object,
|
||||
) -> Result<(usize, usize), InitrdLoadError> {
|
||||
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 mut file = root
|
||||
.open(filename, efi::proto::fp::OPEN_MODE_READ, 0)
|
||||
.map_err(InitrdLoadError::IOError)?;
|
||||
let stat = file.stat(&mut statbuf).map_err(InitrdLoadError::IOError)?;
|
||||
let size = stat.file_size as usize;
|
||||
|
||||
// 1. Try loading right below the kernel
|
||||
@ -39,7 +43,7 @@ pub fn load_somewhere(root: &mut File,
|
||||
}
|
||||
|
||||
// 2. Any location above the kernel
|
||||
for start in ((obj.end + 0x3FFF) & !0xFFF .. 0x100000000).step_by(0x1000) {
|
||||
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)?;
|
||||
@ -47,6 +51,5 @@ pub fn load_somewhere(root: &mut File,
|
||||
}
|
||||
}
|
||||
|
||||
Err(Status::InvalidParameter)
|
||||
Err(InitrdLoadError::NoSpace)
|
||||
}
|
||||
|
||||
|
92
src/main.rs
92
src/main.rs
@ -1,61 +1,61 @@
|
||||
#![feature(asm,const_fn,llvm_asm)]
|
||||
#![feature(asm, const_fn, llvm_asm)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate efi;
|
||||
extern crate core_rt;
|
||||
extern crate char16_literal;
|
||||
extern crate core_rt;
|
||||
extern crate efi;
|
||||
extern crate yboot2_proto;
|
||||
pub (crate) use char16_literal::cstr16;
|
||||
pub(crate) use char16_literal::cstr16;
|
||||
|
||||
use efi::{
|
||||
CStr16,
|
||||
Status,
|
||||
ConfigurationTableEntry,
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
system_table,
|
||||
image_handle,
|
||||
};
|
||||
use yboot2_proto::{LoadProtocol, ProtoV1, MemoryMapInfo};
|
||||
use core::convert::TryInto;
|
||||
use efi::{
|
||||
image_handle, system_table, CStr16, ConfigurationTableEntry, ImageHandle, Status, SystemTable,
|
||||
};
|
||||
use yboot2_proto::{LoadProtocol, MemoryMapInfo, ProtoV1};
|
||||
|
||||
#[macro_use]
|
||||
mod println;
|
||||
mod initrd;
|
||||
mod video;
|
||||
mod mem;
|
||||
mod elf;
|
||||
mod error;
|
||||
mod initrd;
|
||||
mod mem;
|
||||
mod video;
|
||||
|
||||
fn set_efi_mmap<T: LoadProtocol>(data: &mut T, mmap: &efi::MemoryMap) -> efi::Result<()> {
|
||||
use error::BootError;
|
||||
|
||||
fn set_efi_mmap<T: LoadProtocol>(data: &mut T, mmap: &efi::MemoryMap) -> Result<(), BootError> {
|
||||
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()
|
||||
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(())
|
||||
Err(_) => Err(BootError::MemoryMapError(efi::Status::Err)),
|
||||
Ok(()) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> efi::Result<()> {
|
||||
fn main() -> Result<(), BootError> {
|
||||
let mut desc_array = [0u8; 16384];
|
||||
let mut mmap = efi::MemoryMap::new(&mut desc_array);
|
||||
let bs = &system_table().boot_services;
|
||||
|
||||
println!("Getting memory map");
|
||||
bs.get_memory_map(&mut mmap)?;
|
||||
bs.get_memory_map(&mut mmap)
|
||||
.map_err(BootError::MemoryMapError)?;
|
||||
|
||||
println!("Getting RSDP");
|
||||
let rsdp = system_table()
|
||||
.config_iter()
|
||||
.find(|x| matches!(x, ConfigurationTableEntry::Acpi10Table(_)))
|
||||
.map(|x| match x {
|
||||
ConfigurationTableEntry::Acpi10Table(ptr) => ptr,
|
||||
_ => panic!()
|
||||
ConfigurationTableEntry::Acpi10Table(ptr) => ptr,
|
||||
_ => panic!(),
|
||||
});
|
||||
|
||||
let mut root = image_handle().get_boot_path()?.open_partition()?;
|
||||
let mut root = image_handle()
|
||||
.get_boot_path()
|
||||
.map_err(BootError::FileError)?
|
||||
.open_partition()
|
||||
.map_err(BootError::FileError)?;
|
||||
|
||||
// Load kernel
|
||||
let mut obj = elf::Object::open(&mut root, CStr16::from_literal(cstr16!(r"\kernel.elf")))?;
|
||||
@ -64,10 +64,12 @@ fn main() -> efi::Result<()> {
|
||||
|
||||
if (data.get_flags() & yboot2_proto::FLAG_INITRD) != 0 {
|
||||
// Load initrd
|
||||
let (initrd_base, initrd_size) = initrd::load_somewhere(&mut root,
|
||||
let (initrd_base, initrd_size) = initrd::load_somewhere(
|
||||
&mut root,
|
||||
CStr16::from_literal(cstr16!(r"\initrd.img")),
|
||||
&mmap,
|
||||
&obj)?;
|
||||
&obj,
|
||||
)?;
|
||||
|
||||
// Set video mode
|
||||
data.set_initrd(initrd_base, initrd_size);
|
||||
@ -81,23 +83,17 @@ fn main() -> efi::Result<()> {
|
||||
video::set_mode(bs, data)?;
|
||||
|
||||
// Get the new memory map and terminate boot services
|
||||
bs.get_memory_map(&mut mmap)?;
|
||||
bs.exit_boot_services(mmap.key)?;
|
||||
bs.get_memory_map(&mut mmap).map_err(BootError::MemoryMapError)?;
|
||||
bs.exit_boot_services(mmap.key).map_err(BootError::TerminateServicesError)?;
|
||||
set_efi_mmap(data, &mmap)?;
|
||||
|
||||
// Setup upper virtual mapping if requested
|
||||
if (data.get_flags() & yboot2_proto::FLAG_UPPER) != 0 {
|
||||
mem::setup_upper();
|
||||
unsafe {
|
||||
llvm_asm!("xor %rbp, %rbp; jmp *$0"::"{di}"(entry));
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
let entry_fn: unsafe fn () -> ! = core::mem::transmute(entry);
|
||||
entry_fn();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
llvm_asm!("xor %rbp, %rbp; jmp *$0"::"{di}"(entry));
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
@ -105,9 +101,15 @@ fn main() -> efi::Result<()> {
|
||||
extern "C" fn efi_main(ih: *mut ImageHandle, st: *mut SystemTable) -> u64 {
|
||||
efi::init(ih, st);
|
||||
let res = &main();
|
||||
println!("result -> {:?}", res);
|
||||
// Don't return immediately on failure
|
||||
if let Err(err) = res {
|
||||
let bs = &system_table().boot_services;
|
||||
println!("yboot2 error: {}", err);
|
||||
// Delay for 5s so error message can be read
|
||||
bs.stall(5000000);
|
||||
}
|
||||
|
||||
efi::Termination::to_efi(res)
|
||||
efi::Termination::to_efi(&res.as_ref().map_err(efi::Status::from))
|
||||
}
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
54
src/video.rs
54
src/video.rs
@ -1,5 +1,6 @@
|
||||
use yboot2_proto::{LoadProtocol, VideoInfo, video::PixelFormat};
|
||||
use efi::{BootServices, Status, GraphicsOutputProtocol, gop::ModeInformation};
|
||||
use crate::error::BootError;
|
||||
use efi::{gop::ModeInformation, BootServices, GraphicsOutputProtocol, Status};
|
||||
use yboot2_proto::{video::PixelFormat, LoadProtocol, VideoInfo};
|
||||
|
||||
// TODO: "Any" format
|
||||
// TODO: "Text" format
|
||||
@ -7,54 +8,57 @@ use efi::{BootServices, Status, GraphicsOutputProtocol, gop::ModeInformation};
|
||||
fn pixel_to_efi(from: PixelFormat) -> Option<efi::gop::PixelFormat> {
|
||||
use efi::gop::PixelFormat::*;
|
||||
match from {
|
||||
PixelFormat::LfbRgb32 => Some(PixelRedGreenBlueReserved8BitPerColor),
|
||||
PixelFormat::LfbBgr32 => Some(PixelBlueGreenRedReserved8BitPerColor),
|
||||
_ => None
|
||||
PixelFormat::LfbRgb32 => Some(PixelRedGreenBlueReserved8BitPerColor),
|
||||
PixelFormat::LfbBgr32 => Some(PixelBlueGreenRedReserved8BitPerColor),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn pixel_from_efi(from: efi::gop::PixelFormat) -> Option<PixelFormat> {
|
||||
use efi::gop::PixelFormat::*;
|
||||
match from {
|
||||
PixelRedGreenBlueReserved8BitPerColor => Some(PixelFormat::LfbRgb32),
|
||||
PixelBlueGreenRedReserved8BitPerColor => Some(PixelFormat::LfbBgr32),
|
||||
PixelRedGreenBlueReserved8BitPerColor => Some(PixelFormat::LfbRgb32),
|
||||
PixelBlueGreenRedReserved8BitPerColor => Some(PixelFormat::LfbBgr32),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_mode(proto: &GraphicsOutputProtocol,
|
||||
req: &VideoInfo) -> Result<(u32, &'static ModeInformation), Status> {
|
||||
fn find_mode(
|
||||
proto: &GraphicsOutputProtocol,
|
||||
req: &VideoInfo,
|
||||
) -> Result<(u32, &'static ModeInformation), BootError> {
|
||||
let req_format = pixel_to_efi(req.format).unwrap();
|
||||
for (num, info) in proto.mode_iter() {
|
||||
if info.horizontal_resolution == req.width &&
|
||||
info.vertical_resolution == req.height &&
|
||||
info.pixel_format == req_format {
|
||||
if info.horizontal_resolution == req.width
|
||||
&& info.vertical_resolution == req.height
|
||||
&& info.pixel_format == req_format
|
||||
{
|
||||
return Ok((num, info));
|
||||
}
|
||||
}
|
||||
Err(Status::InvalidParameter)
|
||||
Err(BootError::VideoModeUnsupported)
|
||||
}
|
||||
|
||||
pub fn set_mode<T: LoadProtocol>(bs: &BootServices, data: &mut T) -> Result<(), Status> {
|
||||
let gop = bs.locate_protocol::<GraphicsOutputProtocol>()?;
|
||||
pub fn set_mode<T: LoadProtocol>(bs: &BootServices, data: &mut T) -> Result<(), BootError> {
|
||||
let gop = bs
|
||||
.locate_protocol::<GraphicsOutputProtocol>()
|
||||
.map_err(|_| BootError::VideoModeFailed)?;
|
||||
|
||||
match find_mode(gop, data.get_video_info()) {
|
||||
Ok((num, info)) => {
|
||||
let mode = gop.set_mode(num)?;
|
||||
Ok((num, info)) => {
|
||||
let mode = gop.set_mode(num).map_err(|_| BootError::VideoModeFailed)?;
|
||||
|
||||
let info = VideoInfo {
|
||||
width: info.horizontal_resolution,
|
||||
height: info.vertical_resolution,
|
||||
format: pixel_from_efi(info.pixel_format).unwrap(),
|
||||
framebuffer: mode.framebuffer_addr() as u64,
|
||||
pitch: 4 * info.horizontal_resolution as u64
|
||||
width: info.horizontal_resolution,
|
||||
height: info.vertical_resolution,
|
||||
format: pixel_from_efi(info.pixel_format).unwrap(),
|
||||
framebuffer: mode.framebuffer_addr() as u64,
|
||||
pitch: 4 * info.horizontal_resolution as u64,
|
||||
};
|
||||
|
||||
data.set_video_info(&info);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user