diff --git a/mk/aarch64-unknown-uefi.mk b/mk/aarch64-unknown-uefi.mk index 283e6a5f2a3b499004a769ff40adda65a72ba19d..7cd3d959420d38baac107722272584a4991cb057 100644 --- a/mk/aarch64-unknown-uefi.mk +++ b/mk/aarch64-unknown-uefi.mk @@ -56,7 +56,6 @@ $(BUILD)/firmware.rom: qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom $(QEMU) \ -d cpu_reset \ - -d guest_errors \ -no-reboot \ -smp 4 -m 2048 \ -chardev stdio,id=debug,signal=off,mux=on \ diff --git a/mk/x86-unknown-none.mk b/mk/x86-unknown-none.mk index 91bd64de41086621700d192c416b4617736ea2de..790d2747e08066286e8d32ec7036ae2dc74cb8dd 100644 --- a/mk/x86-unknown-none.mk +++ b/mk/x86-unknown-none.mk @@ -47,7 +47,6 @@ $(BUILD)/harddrive.bin: $(BUILD)/bootloader.bin $(BUILD)/filesystem.bin qemu: $(BUILD)/harddrive.bin $(QEMU) \ -d cpu_reset \ - -d guest_errors \ -no-reboot \ -smp 4 -m 2048 \ -chardev stdio,id=debug,signal=off,mux=on \ diff --git a/mk/x86_64-unknown-uefi.mk b/mk/x86_64-unknown-uefi.mk index ee41d971bfc0f58868d0b2577020c2776289e0ef..49332e47d602a7aa5533b4b525904b07588c93ae 100644 --- a/mk/x86_64-unknown-uefi.mk +++ b/mk/x86_64-unknown-uefi.mk @@ -56,7 +56,6 @@ $(BUILD)/firmware.rom: qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom $(QEMU) \ -d cpu_reset \ - -d guest_errors \ -no-reboot \ -smp 4 -m 2048 \ -chardev stdio,id=debug,signal=off,mux=on \ diff --git a/src/main.rs b/src/main.rs index 39451625c52bae1e283a70d9d67bc6b83da86be4..ecd9c8187dcc9216412af6b1d7cf5e21328c654f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,6 @@ impl<'a> Write for SliceWriter<'a> { } #[allow(dead_code)] -#[derive(Debug)] #[repr(packed)] pub struct KernelArgs { kernel_base: u64, @@ -81,25 +80,11 @@ pub struct KernelArgs { acpi_rsdps_size: u64, } -fn main< +fn select_mode< D: Disk, M: Iterator<Item=OsMemoryEntry>, V: Iterator<Item=OsVideoMode> ->(os: &mut dyn Os<D, M, V>) -> (usize, KernelArgs) { - println!("Redox OS Bootloader {} on {}", env!("CARGO_PKG_VERSION"), os.name()); - - let mut fs = os.filesystem(); - - print!("RedoxFS "); - for i in 0..fs.header.1.uuid.len() { - if i == 4 || i == 6 || i == 8 || i == 10 { - print!("-"); - } - - print!("{:>02x}", fs.header.1.uuid[i]); - } - println!(": {} MiB", fs.header.1.size / MIBI as u64); - +>(os: &mut dyn Os<D, M, V>) -> Option<OsVideoMode> { let mut modes = Vec::new(); for mode in os.video_modes() { let mut aspect_w = mode.width; @@ -117,6 +102,10 @@ fn main< )); } + if modes.is_empty() { + return None; + } + // Sort modes by pixel area, reversed modes.sort_by(|a, b| (b.0.width * b.0.height).cmp(&(a.0.width * a.0.height))); @@ -227,6 +216,30 @@ fn main< os.set_text_highlight(false); println!(); + mode_opt +} + +fn main< + D: Disk, + M: Iterator<Item=OsMemoryEntry>, + V: Iterator<Item=OsVideoMode> +>(os: &mut dyn Os<D, M, V>) -> (usize, KernelArgs) { + println!("Redox OS Bootloader {} on {}", env!("CARGO_PKG_VERSION"), os.name()); + + let mut fs = os.filesystem(); + + print!("RedoxFS "); + for i in 0..fs.header.1.uuid.len() { + if i == 4 || i == 6 || i == 8 || i == 10 { + print!("-"); + } + + print!("{:>02x}", fs.header.1.uuid[i]); + } + println!(": {} MiB", fs.header.1.size / MIBI as u64); + + let mode_opt = select_mode(os); + let stack_size = 128 * KIBI; let stack_base = os.alloc_zeroed_page_aligned(stack_size); if stack_base.is_null() { diff --git a/src/os/uefi/arch/aarch64/mod.rs b/src/os/uefi/arch/aarch64/mod.rs index fc888c67bb30366bd263c78acea3b2097ceb029a..9e2a251692bb54e618473613e5b2c07c7b14424f 100644 --- a/src/os/uefi/arch/aarch64/mod.rs +++ b/src/os/uefi/arch/aarch64/mod.rs @@ -1,16 +1,14 @@ -use alloc::{ - string::String, -}; -use core::{mem, ptr, slice}; -use std::fs::find; -use std::proto::Protocol; +use core::{mem, ptr}; use uefi::guid::Guid; -use uefi::memory::MemoryType; use uefi::status::{Error, Result}; +use crate::{ + KernelArgs, + logger::LOGGER, +}; + use super::super::{ - disk::DiskEfi, - display::{Output}, + OsEfi, }; use self::memory_map::memory_map; @@ -19,11 +17,7 @@ use self::paging::paging; mod memory_map; mod paging; -static KERNEL_OFFSET: u64 = 0xFFFF_FF00_0000_0000; - -static KERNEL_PHYSICAL: u64 = 0x4000_0000; -static mut KERNEL_SIZE: u64 = 0; -static mut KERNEL_ENTRY: u64 = 0; +static PHYS_OFFSET: u64 = 0xFFFF800000000000; static mut DTB_PHYSICAL: u64 = 0; @@ -32,22 +26,6 @@ pub extern "C" fn __chkstk() { //TODO } -unsafe fn allocate_zero_pages(pages: usize) -> Result<usize> { - let uefi = std::system_table(); - - let mut ptr = 0; - (uefi.BootServices.AllocatePages)( - 0, // AllocateAnyPages - MemoryType::EfiRuntimeServicesData, // Keeps this memory out of free space list - pages, - &mut ptr - )?; - - ptr::write_bytes(ptr as *mut u8, 0, 4096); - - Ok(ptr) -} - unsafe fn exit_boot_services(key: usize) { let handle = std::handle(); let uefi = std::system_table(); @@ -55,13 +33,6 @@ unsafe fn exit_boot_services(key: usize) { let _ = (uefi.BootServices.ExitBootServices)(handle, key); } -unsafe fn enter() -> ! { - let entry_fn: extern "C" fn(dtb: u64) -> ! = mem::transmute( - KERNEL_PHYSICAL + KERNEL_ENTRY - KERNEL_OFFSET - ); - entry_fn(DTB_PHYSICAL); -} - static DTB_GUID: Guid = Guid(0xb1b621d5, 0xf19c, 0x41a5, [0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]); fn find_dtb() -> Result<()> { @@ -79,143 +50,42 @@ fn find_dtb() -> Result<()> { Err(Error::NotFound) } -fn redoxfs() -> Result<redoxfs::FileSystem<DiskEfi>> { - 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"); +unsafe extern "C" fn kernel_entry( + page_phys: usize, + stack: u64, + func: u64, + args: *const KernelArgs, +) -> ! { + // Read memory map and exit boot services + let key = memory_map(); + exit_boot_services(key); + + // Enable paging + asm!("msr daifset, #2"); + paging(); + + // Call kernel entry + let entry_fn: extern "C" fn(dtb: u64) -> ! = mem::transmute(func); + entry_fn(DTB_PHYSICAL); } -const MB: usize = 1024 * 1024; +pub fn main() -> Result<()> { + LOGGER.init(); -fn inner() -> Result<()> { find_dtb()?; - //TODO: detect page size? - let page_size = 4096; - - { - let mut env = String::new(); - if let Ok(output) = Output::one() { - let mode = &output.0.Mode; - env.push_str(&format!("FRAMEBUFFER_ADDR={:016x}\n", mode.FrameBufferBase)); - env.push_str(&format!("FRAMEBUFFER_WIDTH={:016x}\n", mode.Info.HorizontalResolution)); - env.push_str(&format!("FRAMEBUFFER_HEIGHT={:016x}\n", mode.Info.VerticalResolution)); - } - - println!("Loading Kernel..."); - let kernel = if let Ok((_i, mut kernel_file)) = find("\\redox_bootloader\\kernel") { - let info = kernel_file.info()?; - let len = info.FileSize; - - let kernel = unsafe { - let ptr = allocate_zero_pages((len as usize + page_size - 1) / page_size)?; - slice::from_raw_parts_mut( - ptr as *mut u8, - len as usize - ) - }; - - let mut i = 0; - for mut chunk in kernel.chunks_mut(4 * MB) { - print!("\r{}% - {} MB", i as u64 * 100 / len, i / MB); - - let count = kernel_file.read(&mut chunk)?; - if count == 0 { - break; - } - //TODO: return error instead of assert - assert_eq!(count, chunk.len()); - - i += count; - } - println!("\r{}% - {} MB", i as u64 * 100 / len, i / MB); - - kernel - } else { - let mut fs = redoxfs()?; + let mut os = OsEfi { + st: std::system_table(), + }; - let root = fs.header.1.root; - let node = fs.find_node("kernel", root).map_err(|_| Error::DeviceError)?; - - let len = fs.node_len(node.0).map_err(|_| Error::DeviceError)?; - - let kernel = unsafe { - let ptr = allocate_zero_pages((len as usize + page_size - 1) / page_size)?; - println!("{:X}", ptr); - - slice::from_raw_parts_mut( - ptr as *mut u8, - len as usize - ) - }; - - let mut i = 0; - for mut chunk in kernel.chunks_mut(4 * MB) { - print!("\r{}% - {} MB", i as u64 * 100 / len, i / MB); - - let count = fs.read_node(node.0, i as u64, &mut chunk, 0, 0).map_err(|_| Error::DeviceError)?; - if count == 0 { - break; - } - //TODO: return error instead of assert - assert_eq!(count, chunk.len()); - - i += count; - } - println!("\r{}% - {} MB", i as u64 * 100 / len, i / MB); - - env.push_str(&format!("REDOXFS_BLOCK={:016x}\n", fs.block)); - env.push_str("REDOXFS_UUID="); - for i in 0..fs.header.1.uuid.len() { - if i == 4 || i == 6 || i == 8 || i == 10 { - env.push('-'); - } - - env.push_str(&format!("{:>02x}", fs.header.1.uuid[i])); - } - - kernel - }; - - println!("Copying Kernel..."); - unsafe { - KERNEL_SIZE = kernel.len() as u64; - println!("Size: {}", KERNEL_SIZE); - KERNEL_ENTRY = *(kernel.as_ptr().offset(0x18) as *const u64); - println!("Entry: {:X}", KERNEL_ENTRY); - ptr::copy(kernel.as_ptr(), KERNEL_PHYSICAL as *mut u8, kernel.len()); - } - - println!("Done!"); - } - - unsafe { - let key = memory_map(); - exit_boot_services(key); - } - - unsafe { - asm!("msr daifset, #2"); - paging(); - } + let (page_phys, args) = crate::main(&mut os); unsafe { - enter(); + kernel_entry( + page_phys, + args.stack_base + args.stack_size + PHYS_OFFSET, + ptr::read((args.kernel_base + 0x18) as *const u64), + &args, + ); } } - -pub fn main() -> Result<()> { - inner()?; - - Ok(()) -} diff --git a/src/os/uefi/arch/x86_64/memory_map.rs b/src/os/uefi/arch/x86_64/memory_map.rs index 4e16fe15bfd0c03cfbc1eb5e7373120123a6a15c..3b6e18f0fdc2a4137d353f568318a1c1abada6a1 100644 --- a/src/os/uefi/arch/x86_64/memory_map.rs +++ b/src/os/uefi/arch/x86_64/memory_map.rs @@ -1,82 +1,6 @@ use core::{mem, ptr}; -use log::error; use uefi::memory::{MemoryDescriptor, MemoryType}; -use crate::os::{OsMemoryEntry, OsMemoryKind}; - -pub struct MemoryMapIter { - map: [u8; 4096], - map_size: usize, - descriptor_size: usize, - i: usize, -} - -impl MemoryMapIter { - pub fn new() -> Self { - let uefi = std::system_table(); - - let mut map: [u8; 4096] = [0; 4096]; - let mut map_size = map.len(); - let mut map_key = 0; - let mut descriptor_size = 0; - let mut descriptor_version = 0; - let _ = (uefi.BootServices.GetMemoryMap)( - &mut map_size, - map.as_mut_ptr() as *mut MemoryDescriptor, - &mut map_key, - &mut descriptor_size, - &mut descriptor_version - ); - - Self { - map, - map_size, - descriptor_size, - i: 0, - } - } -} - -impl Iterator for MemoryMapIter { - type Item=OsMemoryEntry; - fn next(&mut self) -> Option<Self::Item> { - if - self.descriptor_size >= mem::size_of::<MemoryDescriptor>() && - self.i < self.map_size/self.descriptor_size - { - let descriptor_ptr = unsafe { self.map.as_ptr().add(self.i * self.descriptor_size) }; - self.i += 1; - - let descriptor = unsafe { ptr::read(descriptor_ptr as *const MemoryDescriptor) }; - let descriptor_type: MemoryType = unsafe { mem::transmute(descriptor.Type) }; - - Some(OsMemoryEntry { - base: descriptor.PhysicalStart.0, - //TODO: do not hard code page size - size: descriptor.NumberOfPages * 4096, - kind: match descriptor_type { - MemoryType::EfiBootServicesCode | - MemoryType::EfiBootServicesData | - MemoryType::EfiConventionalMemory => { - OsMemoryKind::Free - }, - MemoryType::EfiLoaderCode | - MemoryType::EfiLoaderData | - MemoryType::EfiACPIReclaimMemory => { - OsMemoryKind::Reclaim - }, - _ => { - OsMemoryKind::Reserved - } - } - }) - } else { - error!("Unknown memory descriptor size: {}", self.descriptor_size); - None - } - } -} - static MM_BASE: u64 = 0x500; static MM_SIZE: u64 = 0x4B00; diff --git a/src/os/uefi/arch/x86_64/mod.rs b/src/os/uefi/arch/x86_64/mod.rs index 3dab3c687e3c117c245dcd3aa72ebd03b28ef6a4..1eb2d0778be81c53fdd961ab9be59165d70215d7 100644 --- a/src/os/uefi/arch/x86_64/mod.rs +++ b/src/os/uefi/arch/x86_64/mod.rs @@ -1,32 +1,29 @@ -use core::{mem, ops::{ControlFlow, Try}, ptr, slice}; -use std::proto::Protocol; -use std::vec::Vec; -use uefi::status::{Result, Status}; -use uefi::guid::GuidKind; -use uefi::memory::MemoryType; -use uefi::system::SystemTable; -use uefi::text::TextInputKey; +use core::{ + mem, + ptr +}; +use std::{ + vec::Vec, +}; +use uefi::{ + guid::GuidKind, + status::Result, +}; use crate::{ KernelArgs, - Os, - OsKey, - OsVideoMode, logger::LOGGER, }; use super::super::{ - disk::DiskEfi, - display::{EdidActive, Output}, + OsEfi, }; -use self::memory_map::{MemoryMapIter, memory_map}; +use self::memory_map::memory_map; use self::paging::paging_enter; -use self::video_mode::VideoModeIter; mod memory_map; mod paging; -mod video_mode; static PHYS_OFFSET: u64 = 0xFFFF800000000000; @@ -119,173 +116,6 @@ fn find_acpi_table_pointers() { } } -pub struct OsEfi { - st: &'static SystemTable, -} - -fn status_to_result(status: Status) -> Result<usize> { - match status.branch() { - ControlFlow::Continue(ok) => Ok(ok), - ControlFlow::Break(err) => Err(err), - } -} - -impl Os< - DiskEfi, - MemoryMapIter, - VideoModeIter -> for OsEfi { - fn name(&self) -> &str { - "x86_64/UEFI" - } - - fn alloc_zeroed_page_aligned(&self, size: usize) -> *mut u8 { - assert!(size != 0); - - let page_size = self.page_size(); - let pages = (size + page_size - 1) / page_size; - - let ptr = { - let mut ptr = 0; - status_to_result( - (self.st.BootServices.AllocatePages)( - 0, // AllocateAnyPages - MemoryType::EfiRuntimeServicesData, // Keeps this memory out of free space list - pages, - &mut ptr - ) - ).unwrap(); - ptr as *mut u8 - }; - - assert!(!ptr.is_null()); - unsafe { ptr::write_bytes(ptr, 0, pages * page_size) }; - ptr - } - - fn page_size(&self) -> usize { - 4096 - } - - fn filesystem(&self) -> redoxfs::FileSystem<DiskEfi> { - 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, - Err(err) => match err.errno { - // Ignore header not found error - syscall::ENOENT => (), - // Print any other errors - _ => log::error!("Failed to open RedoxFS on block I/O {}: {}", i, err), - } - } - } - panic!("Failed to find RedoxFS"); - } - - fn memory(&self) -> MemoryMapIter { - MemoryMapIter::new() - } - - fn video_modes(&self) -> VideoModeIter { - VideoModeIter::new() - } - - fn set_video_mode(&self, mode: &mut OsVideoMode) { - let output = Output::one().unwrap(); - status_to_result( - (output.0.SetMode)(output.0, mode.id) - ).unwrap(); - - // Update frame buffer base - mode.base = output.0.Mode.FrameBufferBase as u64; - } - - fn best_resolution(&self) -> Option<(u32, u32)> { - //TODO: get this per output - match EdidActive::one() { - Ok(efi_edid) => { - let edid = unsafe { - slice::from_raw_parts(efi_edid.0.Edid, efi_edid.0.SizeOfEdid as usize) - }; - - Some(( - (edid[0x38] as u32) | (((edid[0x3A] as u32) & 0xF0) << 4), - (edid[0x3B] as u32) | (((edid[0x3D] as u32) & 0xF0) << 4), - )) - }, - Err(err) => { - log::warn!("Failed to get EFI EDID: {:?}", err); - - // Fallback to the current output resolution - match Output::one() { - Ok(output) => { - Some(( - output.0.Mode.Info.HorizontalResolution, - output.0.Mode.Info.VerticalResolution, - )) - }, - Err(err) => { - log::error!("Failed to get output: {:?}", err); - None - } - } - } - } - } - - fn get_key(&self) -> OsKey { - //TODO: do not unwrap - - let mut index = 0; - status_to_result( - (self.st.BootServices.WaitForEvent)(1, &self.st.ConsoleIn.WaitForKey, &mut index) - ).unwrap(); - - let mut key = TextInputKey { - ScanCode: 0, - UnicodeChar: 0 - }; - status_to_result( - (self.st.ConsoleIn.ReadKeyStroke)(self.st.ConsoleIn, &mut key) - ).unwrap(); - - match key.ScanCode { - 0 => match key.UnicodeChar { - 13 => OsKey::Enter, - _ => OsKey::Other, - }, - 1 => OsKey::Up, - 2 => OsKey::Down, - 3 => OsKey::Right, - 4 => OsKey::Left, - _ => OsKey::Other, - } - } - - fn get_text_position(&self) -> (usize, usize) { - ( - self.st.ConsoleOut.Mode.CursorColumn as usize, - self.st.ConsoleOut.Mode.CursorRow as usize, - ) - } - - fn set_text_position(&self, x: usize, y: usize) { - status_to_result( - (self.st.ConsoleOut.SetCursorPosition)(self.st.ConsoleOut, x, y) - ).unwrap(); - } - - fn set_text_highlight(&self, highlight: bool) { - let attr = if highlight { 0x70 } else { 0x07 }; - status_to_result( - (self.st.ConsoleOut.SetAttribute)(self.st.ConsoleOut, attr) - ).unwrap(); - } -} unsafe extern "C" fn kernel_entry( page_phys: usize, @@ -314,12 +144,12 @@ unsafe extern "C" fn kernel_entry( pub fn main() -> Result<()> { LOGGER.init(); + find_acpi_table_pointers(); + let mut os = OsEfi { st: std::system_table(), }; - find_acpi_table_pointers(); - let (page_phys, mut args) = crate::main(&mut os); unsafe { diff --git a/src/os/uefi/memory_map.rs b/src/os/uefi/memory_map.rs new file mode 100644 index 0000000000000000000000000000000000000000..5ae3d5cdfc20d026d37500939b53e171ad09f446 --- /dev/null +++ b/src/os/uefi/memory_map.rs @@ -0,0 +1,78 @@ +use core::{mem, ptr}; +use log::error; +use uefi::memory::{MemoryDescriptor, MemoryType}; + +use crate::os::{OsMemoryEntry, OsMemoryKind}; + +pub struct MemoryMapIter { + map: [u8; 4096], + map_size: usize, + descriptor_size: usize, + i: usize, +} + +impl MemoryMapIter { + pub fn new() -> Self { + let uefi = std::system_table(); + + let mut map: [u8; 4096] = [0; 4096]; + let mut map_size = map.len(); + let mut map_key = 0; + let mut descriptor_size = 0; + let mut descriptor_version = 0; + let _ = (uefi.BootServices.GetMemoryMap)( + &mut map_size, + map.as_mut_ptr() as *mut MemoryDescriptor, + &mut map_key, + &mut descriptor_size, + &mut descriptor_version + ); + + Self { + map, + map_size, + descriptor_size, + i: 0, + } + } +} + +impl Iterator for MemoryMapIter { + type Item=OsMemoryEntry; + fn next(&mut self) -> Option<Self::Item> { + if + self.descriptor_size >= mem::size_of::<MemoryDescriptor>() && + self.i < self.map_size/self.descriptor_size + { + let descriptor_ptr = unsafe { self.map.as_ptr().add(self.i * self.descriptor_size) }; + self.i += 1; + + let descriptor = unsafe { ptr::read(descriptor_ptr as *const MemoryDescriptor) }; + let descriptor_type: MemoryType = unsafe { mem::transmute(descriptor.Type) }; + + Some(OsMemoryEntry { + base: descriptor.PhysicalStart.0, + //TODO: do not hard code page size + size: descriptor.NumberOfPages * 4096, + kind: match descriptor_type { + MemoryType::EfiBootServicesCode | + MemoryType::EfiBootServicesData | + MemoryType::EfiConventionalMemory => { + OsMemoryKind::Free + }, + MemoryType::EfiLoaderCode | + MemoryType::EfiLoaderData | + MemoryType::EfiACPIReclaimMemory => { + OsMemoryKind::Reclaim + }, + _ => { + OsMemoryKind::Reserved + } + } + }) + } else { + error!("Unknown memory descriptor size: {}", self.descriptor_size); + None + } + } +} diff --git a/src/os/uefi/mod.rs b/src/os/uefi/mod.rs index c1c4f78ccb4b0434e53b1a07dfcd3e1fd734cd90..74c1f20fdf6da3f42039b73651dc04f2af42b8f9 100644 --- a/src/os/uefi/mod.rs +++ b/src/os/uefi/mod.rs @@ -1,11 +1,211 @@ -use core::ops::Try; -use core::ptr; -use uefi::reset::ResetType; -use uefi::status::{Result, Status}; +use core::{ + ops::{ControlFlow, Try}, + ptr, + slice +}; +use std::{ + proto::Protocol, +}; +use uefi::{ + reset::ResetType, + memory::MemoryType, + status::{Result, Status}, + system::SystemTable, + text::TextInputKey, +}; + +use crate::os::{ + Os, + OsKey, + OsVideoMode, +}; + +use self::{ + disk::DiskEfi, + display::{EdidActive, Output}, + memory_map::MemoryMapIter, + video_mode::VideoModeIter, +}; mod arch; mod disk; mod display; +mod memory_map; +mod video_mode; + +fn status_to_result(status: Status) -> Result<usize> { + match status.branch() { + ControlFlow::Continue(ok) => Ok(ok), + ControlFlow::Break(err) => Err(err), + } +} + +pub struct OsEfi { + st: &'static SystemTable, +} + +impl Os< + DiskEfi, + MemoryMapIter, + VideoModeIter +> for OsEfi { + #[cfg(target_arch = "aarch64")] + fn name(&self) -> &str { + "aarch64/UEFI" + } + + #[cfg(target_arch = "x86_64")] + fn name(&self) -> &str { + "x86_64/UEFI" + } + + fn alloc_zeroed_page_aligned(&self, size: usize) -> *mut u8 { + assert!(size != 0); + + let page_size = self.page_size(); + let pages = (size + page_size - 1) / page_size; + + let ptr = { + let mut ptr = 0; + status_to_result( + (self.st.BootServices.AllocatePages)( + 0, // AllocateAnyPages + MemoryType::EfiRuntimeServicesData, // Keeps this memory out of free space list + pages, + &mut ptr + ) + ).unwrap(); + ptr as *mut u8 + }; + + assert!(!ptr.is_null()); + unsafe { ptr::write_bytes(ptr, 0, pages * page_size) }; + ptr + } + + fn page_size(&self) -> usize { + 4096 + } + + fn filesystem(&self) -> redoxfs::FileSystem<DiskEfi> { + 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, + Err(err) => match err.errno { + // Ignore header not found error + syscall::ENOENT => (), + // Print any other errors + _ => log::error!("Failed to open RedoxFS on block I/O {}: {}", i, err), + } + } + } + panic!("Failed to find RedoxFS"); + } + + fn memory(&self) -> MemoryMapIter { + MemoryMapIter::new() + } + + fn video_modes(&self) -> VideoModeIter { + VideoModeIter::new() + } + + fn set_video_mode(&self, mode: &mut OsVideoMode) { + let output = Output::one().unwrap(); + status_to_result( + (output.0.SetMode)(output.0, mode.id) + ).unwrap(); + + // Update frame buffer base + mode.base = output.0.Mode.FrameBufferBase as u64; + } + + fn best_resolution(&self) -> Option<(u32, u32)> { + //TODO: get this per output + match EdidActive::one() { + Ok(efi_edid) => { + let edid = unsafe { + slice::from_raw_parts(efi_edid.0.Edid, efi_edid.0.SizeOfEdid as usize) + }; + + Some(( + (edid[0x38] as u32) | (((edid[0x3A] as u32) & 0xF0) << 4), + (edid[0x3B] as u32) | (((edid[0x3D] as u32) & 0xF0) << 4), + )) + }, + Err(err) => { + log::warn!("Failed to get EFI EDID: {:?}", err); + + // Fallback to the current output resolution + match Output::one() { + Ok(output) => { + Some(( + output.0.Mode.Info.HorizontalResolution, + output.0.Mode.Info.VerticalResolution, + )) + }, + Err(err) => { + log::error!("Failed to get output: {:?}", err); + None + } + } + } + } + } + + fn get_key(&self) -> OsKey { + //TODO: do not unwrap + + let mut index = 0; + status_to_result( + (self.st.BootServices.WaitForEvent)(1, &self.st.ConsoleIn.WaitForKey, &mut index) + ).unwrap(); + + let mut key = TextInputKey { + ScanCode: 0, + UnicodeChar: 0 + }; + status_to_result( + (self.st.ConsoleIn.ReadKeyStroke)(self.st.ConsoleIn, &mut key) + ).unwrap(); + + match key.ScanCode { + 0 => match key.UnicodeChar { + 13 => OsKey::Enter, + _ => OsKey::Other, + }, + 1 => OsKey::Up, + 2 => OsKey::Down, + 3 => OsKey::Right, + 4 => OsKey::Left, + _ => OsKey::Other, + } + } + + fn get_text_position(&self) -> (usize, usize) { + ( + self.st.ConsoleOut.Mode.CursorColumn as usize, + self.st.ConsoleOut.Mode.CursorRow as usize, + ) + } + + fn set_text_position(&self, x: usize, y: usize) { + status_to_result( + (self.st.ConsoleOut.SetCursorPosition)(self.st.ConsoleOut, x, y) + ).unwrap(); + } + + fn set_text_highlight(&self, highlight: bool) { + let attr = if highlight { 0x70 } else { 0x07 }; + status_to_result( + (self.st.ConsoleOut.SetAttribute)(self.st.ConsoleOut, attr) + ).unwrap(); + } +} fn set_max_mode(output: &uefi::text::TextOutput) -> Result<()> { let mut max_i = None; diff --git a/src/os/uefi/arch/x86_64/video_mode.rs b/src/os/uefi/video_mode.rs similarity index 100% rename from src/os/uefi/arch/x86_64/video_mode.rs rename to src/os/uefi/video_mode.rs