Skip to content
Snippets Groups Projects
Verified Commit 8c7bb57e authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Integrate EFI bootloader

parent 6936228d
No related branches found
No related tags found
No related merge requests found
Showing
with 1405 additions and 60 deletions
......@@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "bit_field"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
[[package]]
name = "bitflags"
version = "1.3.2"
......@@ -47,15 +53,33 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "orbclient"
version = "0.3.21"
source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git?branch=no_std#0cf93f23b88fdeff6561a4f9b4b91798c3c3a4a1"
[[package]]
name = "raw-cpuid"
version = "10.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_bootloader"
version = "0.1.0"
dependencies = [
"linked_list_allocator",
"log",
"orbclient",
"redox_syscall",
"redox_uefi",
"redox_uefi_std",
"redoxfs",
"spin",
"x86",
]
[[package]]
......@@ -67,6 +91,31 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_uefi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c63a3180c5aba47178029b21c1615fbdf87d2bf682669708ea15e9c71eb8935"
[[package]]
name = "redox_uefi_alloc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524f31a58708b6d0ba2d4e734c1dcf14d287307b09118ff07ef25dd504773c7c"
dependencies = [
"redox_uefi",
]
[[package]]
name = "redox_uefi_std"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a520781d9bb97c9802dd196e7a550fafaeea62d94b2351422c3424981d3a2d"
dependencies = [
"redox_uefi",
"redox_uefi_alloc",
]
[[package]]
name = "redoxfs"
version = "0.4.4"
......@@ -107,3 +156,14 @@ name = "uuid"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
[[package]]
name = "x86"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e85eb056bbe47f56d75dc0ccc5fe9c12211ed141292f4d7485d2a7c3dedda09"
dependencies = [
"bit_field",
"bitflags",
"raw-cpuid",
]
......@@ -3,9 +3,15 @@ name = "redox_bootloader"
version = "0.1.0"
edition = "2018"
# UEFI uses bin target
[[bin]]
name = "bootloader"
path = "src/main.rs"
# BIOS uses lib target
[lib]
name = "bootloader"
path = "src/lib.rs"
path = "src/main.rs"
crate-type = ["staticlib"]
[dependencies]
......@@ -14,3 +20,15 @@ log = "0.4.14"
redox_syscall = "0.2.10"
redoxfs = { version = "0.4.4", default-features = false }
spin = "0.9.2"
[target.'cfg(target_os = "uefi")'.dependencies]
redox_uefi = "0.1.2"
redox_uefi_std = "0.1.5"
[target.'cfg(target_os = "uefi")'.dependencies.orbclient]
git = "https://gitlab.redox-os.org/redox-os/orbclient.git"
branch = "no_std"
features = ["no_std"]
[target."x86_64-unknown-uefi".dependencies]
x86 = "0.43.0"
MIT License
Copyright (c) 2017 Redox OS
Copyright (c) 2017-2022 Redox OS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
TARGET?=x86-unknown-none
TARGET?=x86_64-unknown-uefi
BUILD=build/$(TARGET)
export RUST_TARGET_PATH=$(CURDIR)/targets
ifeq ($(TARGET),x86-unknown-none)
export LD=ld -m elf_i386
export OBJCOPY=objcopy
export PARTED=parted
export QEMU=qemu-system-x86_64
all: $(BUILD)/bootloader.bin
else
all:
$(error target $(TARGET) not supported by bootloader yet)
endif
include mk/$(TARGET).mk
clean:
rm -rf build
$(BUILD)/libbootloader.a: Cargo.lock Cargo.toml $(shell find src -type f)
mkdir -p $(BUILD)
cargo rustc --lib --target $(TARGET) --release -- -C soft-float -C debuginfo=2 --emit link=$@
$(BUILD)/bootloader.elf: linkers/$(TARGET).ld $(BUILD)/libbootloader.a
mkdir -p $(BUILD)
$(LD) --gc-sections -z max-page-size=0x1000 -T $< -o $@ $(BUILD)/libbootloader.a && \
$(OBJCOPY) --only-keep-debug $@ $@.sym && \
$(OBJCOPY) --strip-debug $@
$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf $(shell find asm/$(TARGET) -type f)
mkdir -p $(BUILD)
nasm -f bin -o $@ -l $@.lst -D STAGE3=$< -iasm/$(TARGET) asm/$(TARGET)/bootloader.asm
$(BUILD)/filesystem:
mkdir -p $(BUILD)
rm -f $@.partial
......@@ -42,36 +14,9 @@ $(BUILD)/filesystem:
fallocate -l 1MiB $@.partial/kernel
mv $@.partial $@
$(BUILD)/filesystem.bin: $(BUILD)/filesystem
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 255MiB $@.partial
redoxfs-ar $@.partial $<
mv $@.partial $@
$(BUILD)/harddrive.bin: $(BUILD)/bootloader.bin $(BUILD)/filesystem.bin
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 256MiB $@.partial
$(PARTED) -s -a minimal $@.partial mklabel msdos
$(PARTED) -s -a minimal $@.partial mkpart primary 1MiB 100%
dd if=$< of=$@.partial bs=1 count=446 conv=notrunc
dd if=$< of=$@.partial bs=512 skip=1 seek=1 conv=notrunc
dd if=$(BUILD)/filesystem.bin of=$@.partial bs=1MiB seek=1 conv=notrunc
mv $@.partial $@
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 \
-serial chardev:debug \
-mon chardev=debug \
-machine q35 \
-net none \
-enable-kvm \
-cpu host \
-drive file=$<,format=raw
export LD?=ld
export OBJCOPY?=objcopy
export PARTED?=parted
export QEMU?=qemu-system-x86_64
all: $(BUILD)/bootloader.bin
$(BUILD)/libbootloader.a: Cargo.lock Cargo.toml $(shell find src -type f)
mkdir -p $(BUILD)
cargo rustc --lib --target $(TARGET) --release -- -C soft-float -C debuginfo=2 --emit link=$@
$(BUILD)/bootloader.elf: linkers/$(TARGET).ld $(BUILD)/libbootloader.a
mkdir -p $(BUILD)
$(LD) -m elf_i386 --gc-sections -z max-page-size=0x1000 -T $< -o $@ $(BUILD)/libbootloader.a && \
$(OBJCOPY) --only-keep-debug $@ $@.sym && \
$(OBJCOPY) --strip-debug $@
$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf $(shell find asm/$(TARGET) -type f)
mkdir -p $(BUILD)
nasm -f bin -o $@ -l $@.lst -D STAGE3=$< -iasm/$(TARGET) asm/$(TARGET)/bootloader.asm
$(BUILD)/harddrive.bin: $(BUILD)/bootloader.bin $(BUILD)/filesystem.bin
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 256MiB $@.partial
$(PARTED) -s -a minimal $@.partial mklabel msdos
$(PARTED) -s -a minimal $@.partial mkpart primary 1MiB 100%
dd if=$< of=$@.partial bs=1 count=446 conv=notrunc
dd if=$< of=$@.partial bs=512 skip=1 seek=1 conv=notrunc
dd if=$(BUILD)/filesystem.bin of=$@.partial bs=1MiB seek=1 conv=notrunc
mv $@.partial $@
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 \
-serial chardev:debug \
-mon chardev=debug \
-machine q35 \
-net none \
-enable-kvm \
-cpu host \
-drive file=$<,format=raw
export LD?=ld
export OBJCOPY?=objcopy
export PARTED?=parted
export QEMU?=qemu-system-x86_64
all: $(BUILD)/bootloader.efi
$(BUILD)/bootloader.efi: Cargo.lock Cargo.toml $(shell find src -type f)
mkdir -p $(BUILD)
cargo rustc \
-Z build-std=core,alloc \
-Z build-std-features=compiler-builtins-mem \
--target $(TARGET) \
--bin bootloader \
--release \
-- \
-C soft-float \
--emit link=$@
$(BUILD)/esp.bin: $(BUILD)/bootloader.efi
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 64MiB $@.partial
mkfs.vfat -F 32 $@.partial
mmd -i $@.partial efi
mmd -i $@.partial efi/boot
mcopy -i $@.partial $< ::efi/boot/bootx64.efi
mv $@.partial $@
$(BUILD)/harddrive.bin: $(BUILD)/esp.bin $(BUILD)/filesystem.bin
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 320MiB $@.partial
$(PARTED) -s -a minimal $@.partial mklabel gpt
$(PARTED) -s -a minimal $@.partial mkpart ESP FAT32 1MiB 65MiB
$(PARTED) -s -a minimal $@.partial mkpart REDOXFS 65MiB 100%
$(PARTED) -s -a minimal $@.partial toggle 1 boot
dd if=$(BUILD)/esp.bin of=$@.partial bs=1MiB seek=1 conv=notrunc
dd if=$(BUILD)/filesystem.bin of=$@.partial bs=1MiB seek=65 conv=notrunc
mv $@.partial $@
$(BUILD)/firmware.rom:
cp /usr/share/OVMF/OVMF_CODE.fd $@
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 \
-serial chardev:debug \
-mon chardev=debug \
-machine q35 \
-net none \
-enable-kvm \
-cpu host \
-bios $(BUILD)/firmware.rom \
-drive file=$<,format=raw
pub use self::paging::paging_create;
mod paging;
mod panic;
......@@ -2,10 +2,20 @@
#![feature(asm)]
#![feature(lang_items)]
#![feature(llvm_asm)]
#![cfg_attr(
target_os = "uefi",
no_main,
feature(control_flow_enum),
feature(try_trait_v2),
)]
#[macro_use]
#[cfg_attr(target_os = "none", macro_use)]
extern crate alloc;
#[cfg(target_os = "uefi")]
#[macro_use]
extern crate uefi_std as std;
#[macro_use]
mod os;
......
......@@ -27,6 +27,7 @@ mod macros;
mod disk;
mod memory_map;
mod panic;
mod thunk;
mod vbe;
mod vga;
......@@ -331,6 +332,11 @@ pub unsafe extern "C" fn kstart(
}
println!("\rKernel: {}/{} MiB", i / 1024 / 1024, size / 1024 / 1024);
let magic = &kernel[..4];
if magic != b"\x7FELF" {
panic!("Kernel has invalid magic number {:#X?}", magic);
}
kernel
};
......
File moved
use uefi::memory::MemoryDescriptor;
pub unsafe fn memory_map() -> usize {
let uefi = std::system_table();
let mut map: [u8; 65536] = [0; 65536];
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
);
map_key
}
use core::{mem, ptr};
use orbclient::{Color, Renderer};
use std::fs::find;
use std::proto::Protocol;
use uefi::guid::Guid;
use uefi::status::{Error, Result};
use crate::display::{Display, ScaledDisplay, Output};
use crate::image::{self, Image};
use crate::key::{key, Key};
use crate::redoxfs;
use crate::text::TextDisplay;
use self::memory_map::memory_map;
use self::paging::paging;
mod memory_map;
mod paging;
mod partitions;
static KERNEL: &'static str = concat!("\\", env!("BASEDIR"), "\\kernel");
static SPLASHBMP: &'static [u8] = include_bytes!("../../../res/splash.bmp");
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 mut DTB_PHYSICAL: u64 = 0;
#[no_mangle]
pub extern "C" fn __chkstk() {
//TODO
}
unsafe fn exit_boot_services(key: usize) {
let handle = std::handle();
let uefi = std::system_table();
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);
}
fn get_correct_block_io() -> Result<redoxfs::Disk> {
// 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 = redoxfs::Disk::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<()> {
let cfg_tables = std::system_table().config_tables();
for cfg_table in cfg_tables.iter() {
if cfg_table.VendorGuid == DTB_GUID {
unsafe {
DTB_PHYSICAL = cfg_table.VendorTable as u64;
println!("DTB: {:X}", DTB_PHYSICAL);
}
return Ok(());
}
}
println!("Failed to find DTB");
Err(Error::NotFound)
}
fn redoxfs() -> Result<redoxfs::FileSystem> {
// TODO: Scan multiple partitions for a kernel.
redoxfs::FileSystem::open(get_correct_block_io()?)
}
const MB: usize = 1024 * 1024;
fn inner() -> Result<()> {
find_dtb()?;
{
println!("Loading Kernel...");
let (kernel, mut env): (Vec<u8>, String) = {
let (_i, mut kernel_file) = find(KERNEL)?;
let info = kernel_file.info()?;
let len = info.FileSize;
let mut kernel = Vec::with_capacity(len as usize);
let mut buf = vec![0; 4 * MB];
loop {
let percent = kernel.len() as u64 * 100 / len;
print!("\r{}% - {} MB", percent, kernel.len() / MB);
let count = kernel_file.read(&mut buf)?;
if count == 0 {
break;
}
kernel.extend(&buf[.. count]);
}
println!("");
(kernel, String::new())
};
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();
}
unsafe {
enter();
}
}
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>>(splash: &Image, f: F) -> Result<T> {
let mut display = Display::new(Output::one()?);
let mut display = ScaledDisplay::new(&mut display);
{
let bg = Color::rgb(0x4a, 0xa3, 0xfd);
display.set(bg);
{
let x = (display.width() as i32 - splash.width() as i32)/2;
let y = 16;
splash.draw(&mut display, x, y);
}
{
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 + splash.height() as i32 + 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(())
}
pub unsafe fn paging() {
// Disable MMU
asm!(
"mrs x0, sctlr_el1",
"bic x0, x0, 1",
"msr sctlr_el1, x0",
"isb",
lateout("x0") _
);
}
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)
}
}
#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(target_arch = "aarch64")]
pub use self::aarch64::*;
#[cfg(target_arch = "x86_64")]
mod x86_64;
#[cfg(target_arch = "x86_64")]
pub use self::x86_64::*;
use core::{mem, ptr};
use uefi::memory::{MemoryDescriptor, MemoryType};
static MM_BASE: u64 = 0x500;
static MM_SIZE: u64 = 0x4B00;
/// Memory does not exist
pub const MEMORY_AREA_NULL: u32 = 0;
/// Memory is free to use
pub const MEMORY_AREA_FREE: u32 = 1;
/// Memory is reserved
pub const MEMORY_AREA_RESERVED: u32 = 2;
/// Memory is used by ACPI, and can be reclaimed
pub const MEMORY_AREA_ACPI: u32 = 3;
/// A memory map area
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct MemoryArea {
pub base_addr: u64,
pub length: u64,
pub _type: u32,
pub acpi: u32
}
pub unsafe fn memory_map() -> usize {
let uefi = std::system_table();
ptr::write_bytes(MM_BASE as *mut u8, 0, MM_SIZE as usize);
let mut map: [u8; 65536] = [0; 65536];
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
);
if descriptor_size >= mem::size_of::<MemoryDescriptor>() {
for i in 0..map_size/descriptor_size {
let descriptor_ptr = map.as_ptr().offset((i * descriptor_size) as isize);
let descriptor = & *(descriptor_ptr as *const MemoryDescriptor);
let descriptor_type: MemoryType = mem::transmute(descriptor.Type);
let bios_type = match descriptor_type {
MemoryType::EfiLoaderCode |
MemoryType::EfiLoaderData |
MemoryType::EfiBootServicesCode |
MemoryType::EfiBootServicesData |
MemoryType::EfiConventionalMemory => {
MEMORY_AREA_FREE
},
_ => {
MEMORY_AREA_RESERVED
}
};
let bios_area = MemoryArea {
base_addr: descriptor.PhysicalStart.0,
length: descriptor.NumberOfPages * 4096,
_type: bios_type,
acpi: 0,
};
ptr::write((MM_BASE as *mut MemoryArea).offset(i as isize), bios_area);
}
} else {
println!("Unknown memory descriptor size: {}", descriptor_size);
}
map_key
}
use core::{cmp, mem, ptr, slice};
use orbclient::{Color, Renderer};
use std::fs::find;
use std::proto::Protocol;
use std::string::String;
use std::vec::Vec;
use uefi::status::{Error, Result};
use uefi::guid::GuidKind;
use uefi::memory::MemoryType;
use super::super::{
disk::DiskEfi,
display::{Display, ScaledDisplay, Output},
key::{key, Key},
text::TextDisplay,
};
use self::memory_map::memory_map;
use self::paging::{paging_create, paging_enter};
mod memory_map;
mod paging;
mod partitions;
static PHYS_OFFSET: u64 = 0xFFFF800000000000;
static mut KERNEL_PHYS: u64 = 0;
static mut KERNEL_SIZE: u64 = 0;
static mut KERNEL_ENTRY: u64 = 0;
static mut STACK_PHYS: u64 = 0;
static STACK_SIZE: u64 = 0x20000;
static mut ENV_PHYS: u64 = 0;
static mut ENV_SIZE: u64 = 0;
static mut RSDPS_AREA: Option<Vec<u8>> = None;
#[repr(packed)]
pub struct KernelArgs {
kernel_base: u64,
kernel_size: u64,
stack_base: u64,
stack_size: u64,
env_base: u64,
env_size: u64,
acpi_rsdps_base: u64,
acpi_rsdps_size: u64,
}
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();
let _ = (uefi.BootServices.ExitBootServices)(handle, key);
}
unsafe fn enter() -> ! {
let args = KernelArgs {
kernel_base: KERNEL_PHYS,
kernel_size: KERNEL_SIZE,
stack_base: STACK_PHYS,
stack_size: STACK_SIZE,
env_base: ENV_PHYS,
env_size: ENV_SIZE,
acpi_rsdps_base: RSDPS_AREA.as_ref().map(Vec::as_ptr).unwrap_or(core::ptr::null()) as usize as u64 + PHYS_OFFSET,
acpi_rsdps_size: RSDPS_AREA.as_ref().map(Vec::len).unwrap_or(0) as u64,
};
let entry_fn: extern "sysv64" fn(args_ptr: *const KernelArgs) -> ! = mem::transmute(KERNEL_ENTRY);
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> {
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
struct Rsdp {
signature: [u8; 8], // b"RSD PTR "
chksum: u8,
oem_id: [u8; 6],
revision: u8,
rsdt_addr: u32,
// the following fields are only available for ACPI 2.0, and are reserved otherwise
length: u32,
xsdt_addr: u64,
extended_chksum: u8,
_rsvd: [u8; 3],
}
// paging is not enabled at this stage; we can just read the physical address here.
let rsdp_bytes = unsafe { core::slice::from_raw_parts(address as *const u8, core::mem::size_of::<Rsdp>()) };
let rsdp = unsafe { (rsdp_bytes.as_ptr() as *const Rsdp).as_ref::<'static>().unwrap() };
println!("RSDP: {:?}", rsdp);
if rsdp.signature != *b"RSD PTR " {
return Err(Invalid);
}
let mut base_sum = 0u8;
for base_byte in &rsdp_bytes[..20] {
base_sum = base_sum.wrapping_add(*base_byte);
}
if base_sum != 0 {
return Err(Invalid);
}
if rsdp.revision == 2 {
let mut extended_sum = 0u8;
for byte in rsdp_bytes {
extended_sum = extended_sum.wrapping_add(*byte);
}
if extended_sum != 0 {
return Err(Invalid);
}
}
let length = if rsdp.revision == 2 { rsdp.length as usize } else { core::mem::size_of::<Rsdp>() };
Ok(length)
}
fn find_acpi_table_pointers() -> Result<()> {
let rsdps_area = unsafe {
RSDPS_AREA = Some(Vec::new());
RSDPS_AREA.as_mut().unwrap()
};
let cfg_tables = std::system_table().config_tables();
for (address, v2) in cfg_tables.iter().find_map(|cfg_table| if cfg_table.VendorGuid.kind() == GuidKind::Acpi { Some((cfg_table.VendorTable, false)) } else if cfg_table.VendorGuid.kind() == GuidKind::Acpi2 { Some((cfg_table.VendorTable, true)) } else { None }) {
match validate_rsdp(address, v2) {
Ok(length) => {
let align = 8;
rsdps_area.extend(&u32::to_ne_bytes(length as u32));
rsdps_area.extend(unsafe { core::slice::from_raw_parts(address as *const u8, length) });
rsdps_area.resize(((rsdps_area.len() + (align - 1)) / align) * align, 0u8);
}
Err(_) => println!("Found RSDP that wasn't valid at {:p}", address as *const u8),
}
}
Ok(())
}
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)
}
const MB: usize = 1024 * 1024;
fn inner() -> Result<()> {
//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 = {
let mut fs = redoxfs()?;
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
};
unsafe {
KERNEL_PHYS = kernel.as_ptr() as u64;
KERNEL_SIZE = kernel.len() as u64;
KERNEL_ENTRY = *(kernel.as_ptr().offset(0x18) as *const u64);
println!("Kernel {:X}:{:X} entry {:X}", KERNEL_PHYS, KERNEL_SIZE, KERNEL_ENTRY);
}
println!("Allocating stack {:X}", STACK_SIZE);
unsafe {
STACK_PHYS = allocate_zero_pages(STACK_SIZE as usize / page_size)? as u64;
println!("Stack {:X}:{:X}", STACK_PHYS, STACK_SIZE);
}
println!("Allocating env {:X}", env.len());
unsafe {
ENV_PHYS = allocate_zero_pages((env.len() + page_size - 1) / page_size)? as u64;
ENV_SIZE = env.len() as u64;
ptr::copy(env.as_ptr(), ENV_PHYS as *mut u8, env.len());
println!("Env {:X}:{:X}", ENV_PHYS, ENV_SIZE);
}
println!("Parsing and writing ACPI RSDP structures.");
find_acpi_table_pointers();
println!("Done!");
}
println!("Creating page tables");
let page_phys = unsafe {
paging_create(KERNEL_PHYS)?
};
println!("Entering kernel");
unsafe {
let key = memory_map();
exit_boot_services(key);
}
unsafe {
llvm_asm!("cli" : : : "memory" : "intel", "volatile");
paging_enter(page_phys);
}
unsafe {
llvm_asm!("mov rsp, $0" : : "r"(STACK_PHYS + PHYS_OFFSET + STACK_SIZE) : "memory" : "intel", "volatile");
enter();
}
}
fn draw_text(display: &mut ScaledDisplay, mut x: i32, y: i32, text: &str, color: Color) {
for c in text.chars() {
display.char(x, y, c, color);
x += 8;
}
}
fn draw_background(display: &mut ScaledDisplay) {
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 x = (display.width() as i32 - prompt.len() as i32 * 8)/2;
let y = display.height() as i32 - 32;
draw_text(display, x, y, &prompt, Color::rgb(0xff, 0xff, 0xff));
}
}
fn select_mode(output: &mut Output) -> Result<()> {
// Read all available modes
let mut modes = Vec::new();
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;
let mut aspect_w = w;
let mut aspect_h = h;
for i in 2..cmp::min(aspect_w / 2, aspect_h / 2) {
while aspect_w % i == 0 && aspect_h % i == 0 {
aspect_w /= i;
aspect_h /= i;
}
}
//TODO: support resolutions that are not perfect multiples of 4
if w % 4 != 0 {
continue;
}
modes.push((i, w, h, format!("{:>4}x{:<4} {:>3}:{:<3}", w, h, aspect_w, aspect_h)));
}
// Sort modes by pixel area, reversed
modes.sort_by(|a, b| (b.1 * b.2).cmp(&(a.1 * a.2)));
// Find current mode index
let mut selected = output.0.Mode.Mode;
// If there are no modes from querymode, don't change mode
if modes.is_empty() {
return Ok(());
}
let white = Color::rgb(0xff, 0xff, 0xff);
let black = Color::rgb(0x00, 0x00, 0x00);
let rows = 12;
loop {
{
// Create a scaled display
let mut display = Display::new(output);
let mut display = ScaledDisplay::new(&mut display);
draw_background(&mut display);
let off_x = (display.width() as i32 - 60 * 8)/2;
let mut off_y = 16;
draw_text(
&mut display,
off_x, off_y,
"Arrow keys and enter select mode",
white
);
off_y += 24;
let mut row = 0;
let mut col = 0;
for (i, w, h, text) in modes.iter() {
if row >= rows as i32 {
col += 1;
row = 0;
}
let x = off_x + col * 20 * 8;
let y = off_y + row * 16;
let fg = if *i == selected {
display.rect(x - 8, y, text.len() as u32 * 8 + 16, 16, white);
black
} else {
white
};
draw_text(&mut display, x, y, text, fg);
row += 1;
}
display.sync();
}
match key(true)? {
Key::Left => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
if mode_i < rows {
while mode_i < modes.len() {
mode_i += rows;
}
}
mode_i -= rows;
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
Key::Right => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
mode_i += rows;
if mode_i >= modes.len() {
mode_i = mode_i % rows;
}
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
Key::Up => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
if mode_i % rows == 0 {
mode_i += rows;
if mode_i > modes.len() {
mode_i = modes.len();
}
}
mode_i -= 1;
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
Key::Down => {
if let Some(mut mode_i) = modes.iter().position(|x| x.0 == selected) {
mode_i += 1;
if mode_i % rows == 0 {
mode_i -= rows;
}
if mode_i >= modes.len() {
mode_i = mode_i - mode_i % rows;
}
if let Some(new) = modes.get(mode_i) {
selected = new.0;
}
}
},
Key::Enter => {
(output.0.SetMode)(output.0, selected)?;
return Ok(());
},
_ => (),
}
}
}
fn pretty_pipe<T, F: FnMut() -> Result<T>>(output: &mut Output, f: F) -> Result<T> {
let mut display = Display::new(output);
let mut display = ScaledDisplay::new(&mut display);
draw_background(&mut display);
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<()> {
if let Ok(mut output) = Output::one() {
select_mode(&mut output)?;
pretty_pipe(&mut output, inner)?;
} else {
inner()?;
}
Ok(())
}
use core::slice;
use x86::{
controlregs::{self, Cr0, Cr4},
msr,
};
use uefi::status::Result;
unsafe fn paging_allocate() -> Result<&'static mut [u64]> {
let ptr = super::allocate_zero_pages(1)?;
Ok(slice::from_raw_parts_mut(
ptr as *mut u64,
512 // page size divided by u64 size
))
}
pub unsafe fn paging_create(kernel_phys: u64) -> Result<u64> {
// Create PML4
let pml4 = paging_allocate()?;
// Recursive mapping for compatibility
pml4[511] = pml4.as_ptr() as u64 | 1 << 1 | 1;
{
// Create PDP for identity mapping
let pdp = paging_allocate()?;
// Link first user and first kernel PML4 entry to PDP
pml4[0] = pdp.as_ptr() as u64 | 1 << 1 | 1;
pml4[256] = pdp.as_ptr() as u64 | 1 << 1 | 1;
// Identity map 8 GiB pages
for pdp_i in 0..8 {
let pd = paging_allocate()?;
pdp[pdp_i] = pd.as_ptr() as u64 | 1 << 1 | 1;
for pd_i in 0..pd.len() {
let pt = paging_allocate()?;
pd[pd_i] = pt.as_ptr() as u64 | 1 << 1 | 1;
for pt_i in 0..pt.len() {
let addr =
pdp_i as u64 * 0x4000_0000 +
pd_i as u64 * 0x20_0000 +
pt_i as u64 * 0x1000;
pt[pt_i] = addr | 1 << 1 | 1;
}
}
}
}
{
// Create PDP for kernel mapping
let pdp = paging_allocate()?;
// Link second to last PML4 entry to PDP
pml4[510] = pdp.as_ptr() as u64 | 1 << 1 | 1;
// Map 1 GiB at kernel offset
for pdp_i in 0..1 {
let pd = paging_allocate()?;
pdp[pdp_i] = pd.as_ptr() as u64 | 1 << 1 | 1;
for pd_i in 0..pd.len() {
let pt = paging_allocate()?;
pd[pd_i] = pt.as_ptr() as u64 | 1 << 1 | 1;
for pt_i in 0..pt.len() {
let addr =
pdp_i as u64 * 0x4000_0000 +
pd_i as u64 * 0x20_0000 +
pt_i as u64 * 0x1000 +
kernel_phys;
pt[pt_i] = addr | 1 << 1 | 1;
}
}
}
}
Ok(pml4.as_ptr() as u64)
}
pub unsafe fn paging_enter(page_phys: u64) {
// Enable OSXSAVE, FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
let mut cr4 = controlregs::cr4();
cr4 |= Cr4::CR4_ENABLE_OS_XSAVE
| Cr4::CR4_ENABLE_SSE
| Cr4::CR4_ENABLE_GLOBAL_PAGES
| Cr4::CR4_ENABLE_PAE
| Cr4::CR4_ENABLE_PSE;
controlregs::cr4_write(cr4);
// Enable Long mode and NX bit
let mut efer = msr::rdmsr(msr::IA32_EFER);
efer |= 1 << 11 | 1 << 8;
msr::wrmsr(msr::IA32_EFER, efer);
// Set new page map
controlregs::cr3_write(page_phys);
// Enable paging, write protect kernel, protected mode
let mut cr0 = controlregs::cr0();
cr0 |= Cr0::CR0_ENABLE_PAGING | Cr0::CR0_WRITE_PROTECT | Cr0::CR0_PROTECTED_MODE;
controlregs::cr0_write(cr0);
}
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)
}
}
use core::ops::{ControlFlow, Try};
use redoxfs::{BLOCK_SIZE, Disk};
use syscall::{EIO, Error, Result};
use std::proto::Protocol;
use uefi::guid::{Guid, BLOCK_IO_GUID};
use uefi::block_io::BlockIo as UefiBlockIo;
pub struct DiskEfi(pub &'static mut UefiBlockIo);
impl Protocol<UefiBlockIo> for DiskEfi {
fn guid() -> Guid {
BLOCK_IO_GUID
}
fn new(inner: &'static mut UefiBlockIo) -> Self {
Self(inner)
}
}
impl Disk for DiskEfi {
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let block_size = self.0.Media.BlockSize as u64;
let lba = block * BLOCK_SIZE / block_size;
match (self.0.ReadBlocks)(self.0, self.0.Media.MediaId, lba, buffer.len(), buffer.as_mut_ptr()).branch() {
ControlFlow::Continue(_) => Ok(buffer.len()),
ControlFlow::Break(err) => {
println!("DiskEfi::read_at 0x{:X} failed: {:?}", block, err);
Err(Error::new(EIO))
}
}
}
fn write_at(&mut self, block: u64, _buffer: &[u8]) -> Result<usize> {
println!("DiskEfi::write_at 0x{:X} not implemented", block);
Err(Error::new(EIO))
}
fn size(&mut self) -> Result<u64> {
println!("DiskEfi::size not implemented");
Err(Error::new(EIO))
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment