Cleanup of UEFI code

This commit is contained in:
Jeremy Soller
2022-02-08 18:15:13 -07:00
parent d2316290cb
commit 039ab8cd77
7 changed files with 30 additions and 442 deletions
+15 -140
View File
@@ -1,6 +1,5 @@
use alloc::{
string::String,
vec::Vec,
};
use core::{mem, ptr, slice};
use orbclient::{Color, Renderer};
@@ -22,9 +21,6 @@ use self::paging::paging;
mod memory_map;
mod paging;
mod partitions;
static KERNEL: &'static str = "\\redox_bootloader\\kernel";
static KERNEL_OFFSET: u64 = 0xFFFF_FF00_0000_0000;
@@ -63,52 +59,12 @@ unsafe fn exit_boot_services(key: usize) {
}
unsafe fn enter() -> ! {
let entry_fn: extern "C" fn(dtb: u64) -> ! = mem::transmute((
let entry_fn: extern "C" fn(dtb: u64) -> ! = mem::transmute(
KERNEL_PHYSICAL + KERNEL_ENTRY - KERNEL_OFFSET
));
);
entry_fn(DTB_PHYSICAL);
}
fn get_correct_block_io() -> Result<DiskEfi> {
// Get all BlockIo handles.
let mut handles = vec! [uefi::Handle(0); 128];
let mut size = handles.len() * mem::size_of::<uefi::Handle>();
(std::system_table().BootServices.LocateHandle)(uefi::boot::LocateSearchType::ByProtocol, &uefi::guid::BLOCK_IO_GUID, 0, &mut size, handles.as_mut_ptr())?;
let max_size = size / mem::size_of::<uefi::Handle>();
let actual_size = std::cmp::min(handles.len(), max_size);
// Return the handle that seems bootable.
for handle in handles.into_iter().take(actual_size) {
let block_io = DiskEfi::handle_protocol(handle)?;
if !block_io.0.Media.LogicalPartition {
continue;
}
let part = partitions::PartitionProto::handle_protocol(handle)?.0;
if part.sys == 1 {
continue;
}
assert_eq!({part.rev}, partitions::PARTITION_INFO_PROTOCOL_REVISION);
if part.ty == partitions::PartitionProtoDataTy::Gpt as u32 {
let gpt = unsafe { part.info.gpt };
assert_ne!(gpt.part_ty_guid, partitions::ESP_GUID, "detected esp partition again");
if gpt.part_ty_guid == partitions::REDOX_FS_GUID || gpt.part_ty_guid == partitions::LINUX_FS_GUID {
return Ok(block_io);
}
} else if part.ty == partitions::PartitionProtoDataTy::Mbr as u32 {
let mbr = unsafe { part.info.mbr };
if mbr.ty == 0x83 {
return Ok(block_io);
}
} else {
continue;
}
}
panic!("Couldn't find handle for partition");
}
static DTB_GUID: Guid = Guid(0xb1b621d5, 0xf19c, 0x41a5, [0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]);
fn find_dtb() -> Result<()> {
@@ -127,10 +83,19 @@ fn find_dtb() -> Result<()> {
}
fn redoxfs() -> Result<redoxfs::FileSystem<DiskEfi>> {
// TODO: Scan multiple partitions for a kernel.
// TODO: pass block_opt for performance reasons
redoxfs::FileSystem::open(get_correct_block_io()?, None)
.map_err(|_| Error::DeviceError)
for (i, block_io) in DiskEfi::all().into_iter().enumerate() {
if !block_io.0.Media.LogicalPartition {
continue;
}
match redoxfs::FileSystem::open(block_io, Some(0)) {
Ok(ok) => return Ok(ok),
Err(err) => {
log::error!("Failed to open RedoxFS on block I/O {}: {}", i, err);
}
}
}
panic!("Failed to find RedoxFS");
}
const MB: usize = 1024 * 1024;
@@ -252,98 +217,8 @@ fn inner() -> Result<()> {
}
}
fn select_mode(output: &mut Output) -> Result<u32> {
loop {
for i in 0..output.0.Mode.MaxMode {
let mut mode_ptr = ::core::ptr::null_mut();
let mut mode_size = 0;
(output.0.QueryMode)(output.0, i, &mut mode_size, &mut mode_ptr)?;
let mode = unsafe { &mut *mode_ptr };
let w = mode.HorizontalResolution;
let h = mode.VerticalResolution;
print!("\r{}x{}: Is this OK? (y)es/(n)o", w, h);
if key(true)? == Key::Character('y') {
println!("");
return Ok(i);
}
}
}
}
fn pretty_pipe<T, F: FnMut() -> Result<T>>(f: F) -> Result<T> {
let mut output = Output::one()?;
let mut display = Display::new(&mut output);
let mut display = ScaledDisplay::new(&mut display);
{
let bg = Color::rgb(0x4a, 0xa3, 0xfd);
display.set(bg);
{
let prompt = format!(
"Redox Bootloader {} {}",
env!("CARGO_PKG_VERSION"),
env!("TARGET").split('-').next().unwrap_or("")
);
let mut x = (display.width() as i32 - prompt.len() as i32 * 8)/2;
let y = display.height() as i32 - 32;
for c in prompt.chars() {
display.char(x, y, c, Color::rgb(0xff, 0xff, 0xff));
x += 8;
}
}
display.sync();
}
{
let cols = 80;
let off_x = (display.width() as i32 - cols as i32 * 8)/2;
let off_y = 16;
let rows = (display.height() as i32 - 64 - off_y - 1) as usize/16;
display.rect(off_x, off_y, cols as u32 * 8, rows as u32 * 16, Color::rgb(0, 0, 0));
display.sync();
let mut text = TextDisplay::new(display);
text.off_x = off_x;
text.off_y = off_y;
text.cols = cols;
text.rows = rows;
text.pipe(f)
}
}
pub fn main() -> Result<()> {
inner()?;
/* TODO
if let Ok(mut output) = Output::one() {
let mut splash = Image::new(0, 0);
{
println!("Loading Splash...");
if let Ok(image) = image::bmp::parse(&SPLASHBMP) {
splash = image;
}
println!(" Done");
}
/* TODO
let mode = pretty_pipe(&splash, || {
select_mode(&mut output)
})?;
(output.0.SetMode)(output.0, mode)?;
*/
pretty_pipe(&splash, inner)?;
} else {
inner()?;
}
*/
Ok(())
}
-63
View File
@@ -1,63 +0,0 @@
use std::proto::Protocol;
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct PartitionProtoInfoMbr {
pub boot: u8,
pub chs_start: [u8; 3],
pub ty: u8,
pub chs_end: [u8; 3],
pub start_lba: u32,
pub lba_size: u32,
}
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct PartitionProtoInfoGpt {
pub part_ty_guid: [u8; 16],
pub uniq_guid: [u8; 16],
pub start_lba: u64,
pub end_lba: u64,
pub attrs: u64,
pub name: [u16; 36],
// reserved until end of block
}
#[repr(packed)]
#[derive(Clone, Copy)]
pub union PartitionProtoDataInfo {
pub mbr: PartitionProtoInfoMbr,
pub gpt: PartitionProtoInfoGpt,
}
#[repr(packed)]
pub struct PartitionProtoData {
pub rev: u32,
pub ty: u32,
pub sys: u8,
pub resv: [u8; 7],
pub info: PartitionProtoDataInfo,
}
pub const PARTITION_INFO_PROTOCOL_REVISION: u32 = 0x1000;
pub const ESP_GUID: [u8; 16] = [0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, 0xba, 0x4b, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b]; // c12a7328-f81f-11d2-bA4b-00a0c93ec93b
pub const LINUX_FS_GUID: [u8; 16] = [0xaf, 0x3d, 0xc6, 0xf, 0x83, 0x84, 0x72, 0x47, 0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4]; // 0fc63daf-8483-4772-8e79-3d69d8477de4
pub const REDOX_FS_GUID: [u8; 16] = [0xfd, 0x98, 0x78, 0x52, 0xe3, 0xff, 0xc2, 0x42, 0xe3, 0x96, 0x10, 0x5b, 0xa6, 0x3f, 0x5a, 0xbf]; // 527898fd-ffe3-42c2-96e3-bf5a3fa65b10
#[repr(u32)]
pub enum PartitionProtoDataTy {
Other = 0,
Mbr = 1,
Gpt = 2,
}
pub struct PartitionProto(pub &'static mut PartitionProtoData);
impl Protocol<PartitionProtoData> for PartitionProto {
fn guid() -> uefi::guid::Guid {
uefi::guid::Guid(0x8cf2f62c, 0xbc9b, 0x4821, [0x80, 0x8d, 0xec, 0x9e, 0xc4, 0x21, 0xa1, 0xa0])
}
fn new(inner: &'static mut PartitionProtoData) -> Self {
Self(inner)
}
}
+14 -46
View File
@@ -20,7 +20,6 @@ use self::paging::{paging_create, paging_enter};
mod memory_map;
mod paging;
mod partitions;
static PHYS_OFFSET: u64 = 0xFFFF800000000000;
@@ -88,46 +87,6 @@ unsafe fn enter() -> ! {
entry_fn(&args);
}
fn get_correct_block_io() -> Result<DiskEfi> {
// Get all BlockIo handles.
let mut handles = vec! [uefi::Handle(0); 128];
let mut size = handles.len() * mem::size_of::<uefi::Handle>();
(std::system_table().BootServices.LocateHandle)(uefi::boot::LocateSearchType::ByProtocol, &uefi::guid::BLOCK_IO_GUID, 0, &mut size, handles.as_mut_ptr())?;
let max_size = size / mem::size_of::<uefi::Handle>();
let actual_size = std::cmp::min(handles.len(), max_size);
// Return the handle that seems bootable.
for handle in handles.into_iter().take(actual_size) {
let block_io = DiskEfi::handle_protocol(handle)?;
if !block_io.0.Media.LogicalPartition {
continue;
}
let part = partitions::PartitionProto::handle_protocol(handle)?.0;
if part.sys == 1 {
continue;
}
assert_eq!({part.rev}, partitions::PARTITION_INFO_PROTOCOL_REVISION);
if part.ty == partitions::PartitionProtoDataTy::Gpt as u32 {
let gpt = unsafe { part.info.gpt };
assert_ne!(gpt.part_ty_guid, partitions::ESP_GUID, "detected esp partition again");
if gpt.part_ty_guid == partitions::REDOX_FS_GUID || gpt.part_ty_guid == partitions::LINUX_FS_GUID {
return Ok(block_io);
}
} else if part.ty == partitions::PartitionProtoDataTy::Mbr as u32 {
let mbr = unsafe { part.info.mbr };
if mbr.ty == 0x83 {
return Ok(block_io);
}
} else {
continue;
}
}
panic!("Couldn't find handle for partition");
}
struct Invalid;
fn validate_rsdp(address: usize, v2: bool) -> core::result::Result<usize, Invalid> {
@@ -202,10 +161,19 @@ fn find_acpi_table_pointers() -> Result<()> {
}
fn redoxfs() -> Result<redoxfs::FileSystem<DiskEfi>> {
// TODO: Scan multiple partitions for a kernel.
// TODO: pass block_opt for performance reasons
redoxfs::FileSystem::open(get_correct_block_io()?, None)
.map_err(|_| Error::DeviceError)
for (i, block_io) in DiskEfi::all().into_iter().enumerate() {
if !block_io.0.Media.LogicalPartition {
continue;
}
match redoxfs::FileSystem::open(block_io, Some(0)) {
Ok(ok) => return Ok(ok),
Err(err) => {
log::error!("Failed to open RedoxFS on block I/O {}: {}", i, err);
}
}
}
panic!("Failed to find RedoxFS");
}
const MB: usize = 1024 * 1024;
@@ -434,7 +402,7 @@ fn select_mode(output: &mut Output) -> Result<()> {
let mut row = 0;
let mut col = 0;
for (i, w, h, text) in modes.iter() {
for (i, _w, _h, text) in modes.iter() {
if row >= rows as i32 {
col += 1;
row = 0;
-63
View File
@@ -1,63 +0,0 @@
use std::proto::Protocol;
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct PartitionProtoInfoMbr {
pub boot: u8,
pub chs_start: [u8; 3],
pub ty: u8,
pub chs_end: [u8; 3],
pub start_lba: u32,
pub lba_size: u32,
}
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct PartitionProtoInfoGpt {
pub part_ty_guid: [u8; 16],
pub uniq_guid: [u8; 16],
pub start_lba: u64,
pub end_lba: u64,
pub attrs: u64,
pub name: [u16; 36],
// reserved until end of block
}
#[repr(packed)]
#[derive(Clone, Copy)]
pub union PartitionProtoDataInfo {
pub mbr: PartitionProtoInfoMbr,
pub gpt: PartitionProtoInfoGpt,
}
#[repr(packed)]
pub struct PartitionProtoData {
pub rev: u32,
pub ty: u32,
pub sys: u8,
pub resv: [u8; 7],
pub info: PartitionProtoDataInfo,
}
pub const PARTITION_INFO_PROTOCOL_REVISION: u32 = 0x1000;
pub const ESP_GUID: [u8; 16] = [0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, 0xba, 0x4b, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b]; // c12a7328-f81f-11d2-bA4b-00a0c93ec93b
pub const LINUX_FS_GUID: [u8; 16] = [0xaf, 0x3d, 0xc6, 0xf, 0x83, 0x84, 0x72, 0x47, 0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4]; // 0fc63daf-8483-4772-8e79-3d69d8477de4
pub const REDOX_FS_GUID: [u8; 16] = [0xfd, 0x98, 0x78, 0x52, 0xe3, 0xff, 0xc2, 0x42, 0xe3, 0x96, 0x10, 0x5b, 0xa6, 0x3f, 0x5a, 0xbf]; // 527898fd-ffe3-42c2-96e3-bf5a3fa65b10
#[repr(u32)]
pub enum PartitionProtoDataTy {
Other = 0,
Mbr = 1,
Gpt = 2,
}
pub struct PartitionProto(pub &'static mut PartitionProtoData);
impl Protocol<PartitionProtoData> for PartitionProto {
fn guid() -> uefi::guid::Guid {
uefi::guid::Guid(0x8cf2f62c, 0xbc9b, 0x4821, [0x80, 0x8d, 0xec, 0x9e, 0xc4, 0x21, 0xa1, 0xa0])
}
fn new(inner: &'static mut PartitionProtoData) -> Self {
Self(inner)
}
}
-1
View File
@@ -7,7 +7,6 @@ mod arch;
mod disk;
mod display;
mod key;
pub mod null;
pub mod text;
fn set_max_mode(output: &uefi::text::TextOutput) -> Result<()> {
-128
View File
@@ -1,128 +0,0 @@
use core::mem;
use core::ops::Deref;
use std::boxed::Box;
use uefi::Handle;
use uefi::boot::InterfaceType;
use uefi::guid::SIMPLE_TEXT_OUTPUT_GUID;
use uefi::status::{Result, Status};
use uefi::text::TextOutputMode;
#[repr(C)]
#[allow(non_snake_case)]
pub struct NullDisplay {
pub Reset: extern "win64" fn(&mut NullDisplay, bool) -> Status,
pub OutputString: extern "win64" fn(&mut NullDisplay, *const u16) -> Status,
pub TestString: extern "win64" fn(&mut NullDisplay, *const u16) -> Status,
pub QueryMode: extern "win64" fn(&mut NullDisplay, usize, &mut usize, &mut usize) -> Status,
pub SetMode: extern "win64" fn(&mut NullDisplay, usize) -> Status,
pub SetAttribute: extern "win64" fn(&mut NullDisplay, usize) -> Status,
pub ClearScreen: extern "win64" fn(&mut NullDisplay) -> Status,
pub SetCursorPosition: extern "win64" fn(&mut NullDisplay, usize, usize) -> Status,
pub EnableCursor: extern "win64" fn(&mut NullDisplay, bool) -> Status,
pub Mode: &'static TextOutputMode,
pub mode: Box<TextOutputMode>,
}
extern "win64" fn reset(_output: &mut NullDisplay, _extra: bool) -> Status {
Status(0)
}
extern "win64" fn output_string(_output: &mut NullDisplay, _string: *const u16) -> Status {
Status(0)
}
extern "win64" fn test_string(_output: &mut NullDisplay, _string: *const u16) -> Status {
Status(0)
}
extern "win64" fn query_mode(_output: &mut NullDisplay, _mode: usize, columns: &mut usize, rows: &mut usize) -> Status {
*columns = 80;
*rows = 30;
Status(0)
}
extern "win64" fn set_mode(_output: &mut NullDisplay, _mode: usize) -> Status {
Status(0)
}
extern "win64" fn set_attribute(output: &mut NullDisplay, attribute: usize) -> Status {
output.mode.Attribute = attribute as i32;
Status(0)
}
extern "win64" fn clear_screen(_output: &mut NullDisplay) -> Status {
Status(0)
}
extern "win64" fn set_cursor_position(output: &mut NullDisplay, column: usize, row: usize) -> Status {
output.mode.CursorColumn = column as i32;
output.mode.CursorRow = row as i32;
Status(0)
}
extern "win64" fn enable_cursor(output: &mut NullDisplay, enable: bool) -> Status {
output.mode.CursorVisible = enable;
Status(0)
}
impl NullDisplay {
pub fn new() -> NullDisplay {
let mode = Box::new(TextOutputMode {
MaxMode: 0,
Mode: 0,
Attribute: 0,
CursorColumn: 0,
CursorRow: 0,
CursorVisible: false,
});
NullDisplay {
Reset: reset,
OutputString: output_string,
TestString: test_string,
QueryMode: query_mode,
SetMode: set_mode,
SetAttribute: set_attribute,
ClearScreen: clear_screen,
SetCursorPosition: set_cursor_position,
EnableCursor: enable_cursor,
Mode: unsafe { mem::transmute(&*mode.deref()) },
mode: mode
}
}
pub fn pipe<T, F: FnMut() -> Result<T>>(&mut self, mut f: F) -> Result<T> {
let uefi = unsafe { std::system_table_mut() };
let stdout = self as *mut _;
let mut stdout_handle = Handle(0);
(uefi.BootServices.InstallProtocolInterface)(&mut stdout_handle, &SIMPLE_TEXT_OUTPUT_GUID, InterfaceType::Native, stdout as usize)?;
let old_stdout_handle = uefi.ConsoleOutHandle;
let old_stdout = uefi.ConsoleOut as *mut _;
let old_stderr_handle = uefi.ConsoleErrorHandle;
let old_stderr = uefi.ConsoleError as *mut _;
uefi.ConsoleOutHandle = stdout_handle;
uefi.ConsoleOut = unsafe { mem::transmute(&mut *stdout) };
uefi.ConsoleErrorHandle = stdout_handle;
uefi.ConsoleError = unsafe { mem::transmute(&mut *stdout) };
let res = f();
uefi.ConsoleOutHandle = old_stdout_handle;
uefi.ConsoleOut = unsafe { mem::transmute(&mut *old_stdout) };
uefi.ConsoleErrorHandle = old_stderr_handle;
uefi.ConsoleError = unsafe { mem::transmute(&mut *old_stderr) };
let _ = (uefi.BootServices.UninstallProtocolInterface)(stdout_handle, &SIMPLE_TEXT_OUTPUT_GUID, stdout as usize);
res
}
}
pub fn pipe<T, F: FnMut() -> Result<T>>(f: F) -> Result<T> {
NullDisplay::new().pipe(f)
}