From d2316290cb8ceb66423afaf04cc5830756ecefe4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 8 Feb 2022 16:46:39 -0700 Subject: [PATCH] Get aarch64 UEFI bootloader building --- mk/aarch64-unknown-uefi.mk | 56 ++++++++++++ mk/x86_64-unknown-uefi.mk | 2 - src/os/uefi/arch/aarch64/mod.rs | 146 +++++++++++++++++++++++------- src/os/uefi/arch/x86_64/mod.rs | 3 +- targets/aarch64-unknown-uefi.json | 25 +++++ 5 files changed, 196 insertions(+), 36 deletions(-) create mode 100644 mk/aarch64-unknown-uefi.mk create mode 100644 targets/aarch64-unknown-uefi.json diff --git a/mk/aarch64-unknown-uefi.mk b/mk/aarch64-unknown-uefi.mk new file mode 100644 index 0000000000..6c0b741ded --- /dev/null +++ b/mk/aarch64-unknown-uefi.mk @@ -0,0 +1,56 @@ +export PARTED?=parted +export QEMU?=qemu-system-aarch64 + +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/bootaa64.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: + wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd -O $@ + +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 virt \ + -net none \ + -cpu cortex-a57 \ + -bios $(BUILD)/firmware.rom \ + -drive file=$<,format=raw diff --git a/mk/x86_64-unknown-uefi.mk b/mk/x86_64-unknown-uefi.mk index 9c0fa31851..7d66b2c11e 100644 --- a/mk/x86_64-unknown-uefi.mk +++ b/mk/x86_64-unknown-uefi.mk @@ -1,5 +1,3 @@ -export LD?=ld -export OBJCOPY?=objcopy export PARTED?=parted export QEMU?=qemu-system-x86_64 diff --git a/src/os/uefi/arch/aarch64/mod.rs b/src/os/uefi/arch/aarch64/mod.rs index 5c1818a6fa..474484222b 100644 --- a/src/os/uefi/arch/aarch64/mod.rs +++ b/src/os/uefi/arch/aarch64/mod.rs @@ -1,15 +1,21 @@ -use core::{mem, ptr}; +use alloc::{ + string::String, + vec::Vec, +}; +use core::{mem, ptr, slice}; use orbclient::{Color, Renderer}; use std::fs::find; use std::proto::Protocol; use uefi::guid::Guid; +use uefi::memory::MemoryType; 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 super::super::{ + disk::DiskEfi, + display::{Display, ScaledDisplay, Output}, + key::{key, Key}, + text::TextDisplay, +}; use self::memory_map::memory_map; use self::paging::paging; @@ -18,8 +24,7 @@ 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: &'static str = "\\redox_bootloader\\kernel"; static KERNEL_OFFSET: u64 = 0xFFFF_FF00_0000_0000; @@ -34,6 +39,22 @@ pub extern "C" fn __chkstk() { //TODO } +unsafe fn allocate_zero_pages(pages: usize) -> Result { + 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(); @@ -48,7 +69,7 @@ unsafe fn enter() -> ! { entry_fn(DTB_PHYSICAL); } -fn get_correct_block_io() -> Result { +fn get_correct_block_io() -> Result { // Get all BlockIo handles. let mut handles = vec! [uefi::Handle(0); 128]; let mut size = handles.len() * mem::size_of::(); @@ -60,7 +81,7 @@ fn get_correct_block_io() -> Result { // Return the handle that seems bootable. for handle in handles.into_iter().take(actual_size) { - let block_io = redoxfs::Disk::handle_protocol(handle)?; + let block_io = DiskEfi::handle_protocol(handle)?; if !block_io.0.Media.LogicalPartition { continue; } @@ -105,9 +126,11 @@ fn find_dtb() -> Result<()> { Err(Error::NotFound) } -fn redoxfs() -> Result { +fn redoxfs() -> Result> { // TODO: Scan multiple partitions for a kernel. - redoxfs::FileSystem::open(get_correct_block_io()?) + // TODO: pass block_opt for performance reasons + redoxfs::FileSystem::open(get_correct_block_io()?, None) + .map_err(|_| Error::DeviceError) } const MB: usize = 1024 * 1024; @@ -115,28 +138,91 @@ const MB: usize = 1024 * 1024; 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, mut env): (Vec, String) = { - let (_i, mut kernel_file) = find(KERNEL)?; + let kernel = if let Ok((_i, mut kernel_file)) = find("\\redox_bootloader\\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)?; + 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()); - kernel.extend(&buf[.. count]); + i += count; } - println!(""); + println!("\r{}% - {} MB", i as u64 * 100 / len, i / MB); - (kernel, String::new()) + kernel + } else { + 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 }; println!("Copying Kernel..."); @@ -188,9 +274,9 @@ fn select_mode(output: &mut Output) -> Result { } } -fn pretty_pipe Result>(splash: &Image, f: F) -> Result { - let mut display = Display::new(Output::one()?); - +fn pretty_pipe Result>(f: F) -> Result { + let mut output = Output::one()?; + let mut display = Display::new(&mut output); let mut display = ScaledDisplay::new(&mut display); { @@ -198,12 +284,6 @@ fn pretty_pipe Result>(splash: &Image, f: F) -> Result { 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 {} {}", @@ -224,7 +304,7 @@ fn pretty_pipe Result>(splash: &Image, f: F) -> Result { { 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 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(); diff --git a/src/os/uefi/arch/x86_64/mod.rs b/src/os/uefi/arch/x86_64/mod.rs index aba74d9ea2..c7c2dfcb27 100644 --- a/src/os/uefi/arch/x86_64/mod.rs +++ b/src/os/uefi/arch/x86_64/mod.rs @@ -204,7 +204,8 @@ fn find_acpi_table_pointers() -> Result<()> { fn redoxfs() -> Result> { // 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) + redoxfs::FileSystem::open(get_correct_block_io()?, None) + .map_err(|_| Error::DeviceError) } const MB: usize = 1024 * 1024; diff --git a/targets/aarch64-unknown-uefi.json b/targets/aarch64-unknown-uefi.json new file mode 100644 index 0000000000..281059c643 --- /dev/null +++ b/targets/aarch64-unknown-uefi.json @@ -0,0 +1,25 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "default-hidden-visibility": true, + "emit-debug-gdb-scripts": false, + "exe-suffix": ".efi", + "executables": true, + "is-like-windows": true, + "linker": "rust-lld", + "linker-flavor": "lld-link", + "llvm-target": "aarch64-pc-windows-msvc", + "os": "uefi", + "panic-strategy": "abort", + "pre-link-args": { + "lld-link": [ + "/subsystem:EFI_Application", + "/entry:efi_main", + "/machine:arm64" + ] + }, + "stack_probes": true, + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64" +}