Exit UEFI boot services and halt.
* Add editorconfig. * Add emacs backup files to gitignore. * Use x86_64 package instead of raw asm. * Set rust toolchain to default to nightly. * Add support for release builds to run.sh. * Mention minimum system requirements to README.master
parent
6c806fc9ae
commit
0ef35c4653
|
@ -0,0 +1,8 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
|
@ -1,2 +1,3 @@
|
||||||
/target
|
/target
|
||||||
/drive
|
/drive
|
||||||
|
*~
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -18,6 +24,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"uefi",
|
"uefi",
|
||||||
|
"x86_64",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -75,7 +82,7 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85061f4e43545a613c0da6b87725bf23f8da8613cf2473719c4f71a270c4ce8a"
|
checksum = "85061f4e43545a613c0da6b87725bf23f8da8613cf2473719c4f71a270c4ce8a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field 0.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -106,3 +113,13 @@ name = "unicode-xid"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_64"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9144cdef072afe8afcbc511be8f421de5b3eb9f4b8ff7abff369bee38f91e7e3"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field 0.9.0",
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
|
@ -7,3 +7,4 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" }
|
compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" }
|
||||||
uefi = "0.4.6"
|
uefi = "0.4.6"
|
||||||
|
x86_64 = "0.11.1"
|
||||||
|
|
|
@ -8,6 +8,11 @@ rather than through a traditional operating system.
|
||||||
I don't seriously expect to ever accomplish that, so for now I'm probably just going to...
|
I don't seriously expect to ever accomplish that, so for now I'm probably just going to...
|
||||||
make a forth or something.
|
make a forth or something.
|
||||||
|
|
||||||
|
## System Requirements
|
||||||
|
Other configurations may work, but only these systems are regularly tested.
|
||||||
|
* CPU: x86_64 QEMU, OVMF UEFI.
|
||||||
|
* Memory: 128 MB. (64 MB appears to be the minimum required to load OVMF at all. Real hardware might require less?)
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
bootproof runs on x86_64 UEFI. You may either boot the program directly on your own computer or use an emulator.
|
bootproof runs on x86_64 UEFI. You may either boot the program directly on your own computer or use an emulator.
|
||||||
|
|
||||||
|
@ -15,7 +20,7 @@ Make sure you have the `cargo-xbuild` crate installed and nightly Rust so you ca
|
||||||
|
|
||||||
First, build with:
|
First, build with:
|
||||||
```
|
```
|
||||||
cargo +nightly xbuild --target x86_64-unknown-uefi
|
cargo xbuild --release --target x86_64-unknown-uefi
|
||||||
```
|
```
|
||||||
|
|
||||||
And to run, simply `./run.sh`.
|
And to run, `./run.sh` will launch bootproof in QEMU.
|
||||||
|
|
3
run.sh
3
run.sh
|
@ -1,4 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
profile=${1:-"debug"}
|
||||||
mkdir -p drive/EFI/Boot
|
mkdir -p drive/EFI/Boot
|
||||||
cp target/x86_64-unknown-uefi/debug/bootproof.efi drive/EFI/Boot/BootX64.efi
|
cp "target/x86_64-unknown-uefi/$profile/bootproof.efi" drive/EFI/Boot/BootX64.efi
|
||||||
qemu-system-x86_64 -nodefaults -machine "q35,accel=kvm:tcg" -smp 8 -m 128M -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" -drive "format=raw,file=fat:rw:drive" -serial stdio -display none
|
qemu-system-x86_64 -nodefaults -machine "q35,accel=kvm:tcg" -smp 8 -m 128M -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on" -drive "if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd,readonly=on" -drive "format=raw,file=fat:rw:drive" -serial stdio -display none
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
nightly
|
91
src/main.rs
91
src/main.rs
|
@ -1,36 +1,93 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(abi_efiapi)]
|
#![feature(abi_efiapi)]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
use core::mem;
|
||||||
|
use core::slice;
|
||||||
use core::writeln;
|
use core::writeln;
|
||||||
use uefi::prelude::*;
|
use uefi::prelude::*;
|
||||||
|
use uefi::table::boot::{AllocateType, MemoryDescriptor, MemoryType};
|
||||||
|
use x86_64::instructions;
|
||||||
|
|
||||||
|
enum LoggerStdio {
|
||||||
|
// It is impossible to get ownership of an Output,
|
||||||
|
// so instead we must pass in the entire boot system table.
|
||||||
|
Boot(SystemTable<Boot>),
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn halt() -> ! {
|
||||||
|
instructions::interrupts::disable();
|
||||||
|
loop { instructions::hlt(); }
|
||||||
|
}
|
||||||
|
|
||||||
// Required for use by the panic handler.
|
// Required for use by the panic handler.
|
||||||
// This should not be used anywhere else.
|
// This should not be used anywhere else.
|
||||||
static mut global_st: Option<*mut SystemTable<Boot>> = None;
|
static mut LOGGER_STDIO: LoggerStdio = LoggerStdio::None;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
let st = unsafe { &global_st.unwrap().read() };
|
match unsafe { &LOGGER_STDIO } {
|
||||||
writeln!(st.stderr(), "stderr: {}", info);
|
LoggerStdio::Boot(st) => {
|
||||||
writeln!(st.stdout(), "stdout: {}", info);
|
writeln!(st.stderr(), "{}", info).unwrap();
|
||||||
|
},
|
||||||
loop {}
|
LoggerStdio::None => {
|
||||||
|
// There's pretty much nothing we can do in this case.
|
||||||
|
// What are we supposed to do-- panic?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(st: &SystemTable<Boot>, _handle: Handle) {
|
||||||
|
let stdout = st.stdout();
|
||||||
|
|
||||||
|
stdout.reset(false).expect_success("Failed to reset UEFI stdout.");
|
||||||
|
writeln!(stdout, "Booting...").unwrap();
|
||||||
|
|
||||||
|
writeln!(stdout, "Exiting the UEFI boot services.").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(st: SystemTable<uefi::table::Runtime>, mmap: uefi::table::boot::MemoryMapIter) -> ! {
|
||||||
|
halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn efi_main(handle: Handle, st: SystemTable<Boot>) -> Status {
|
fn efi_main(handle: Handle, st_boot: SystemTable<Boot>) -> Status {
|
||||||
let mut g_st = unsafe { st.unsafe_clone() };
|
// Tasks that require the UEFI boot services.
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
global_st = Some(&mut g_st);
|
LOGGER_STDIO = LoggerStdio::Boot(st_boot.unsafe_clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
st.stdout().reset(false).expect_success("Failed to reset UEFI stdout.");
|
setup(&st_boot, handle);
|
||||||
writeln!(st.stdout(), "Hello, world!");
|
|
||||||
|
// Exit the UEFI boot services.
|
||||||
loop {}
|
|
||||||
|
// The memory map buffer must live at least as long as the memory map iterator.
|
||||||
Status::SUCCESS
|
let mmap_buf;
|
||||||
}
|
let (st_runtime, mmap) = {
|
||||||
|
let bs = st_boot.boot_services();
|
||||||
|
|
||||||
|
// More allocations can happen between the allocation of the buffer and the buffer being filled,
|
||||||
|
// so arbitrarily add space for 8 more memory descriptors just to make sure there's enough.
|
||||||
|
let mmap_buf_size = bs.memory_map_size() + 8 * mem::size_of::<MemoryDescriptor>();
|
||||||
|
mmap_buf = bs.allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, mmap_buf_size)
|
||||||
|
.expect_success("Could not allocate space for UEFI memory map.");
|
||||||
|
let mmap_buf_slice = unsafe { slice::from_raw_parts_mut(mmap_buf as *mut u8, mmap_buf_size) };
|
||||||
|
st_boot.exit_boot_services(handle, mmap_buf_slice).expect_success("Failed to exit the UEFI boot services.")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tasks that do not require the UEFI boot services.
|
||||||
|
|
||||||
|
// I do not currently have an adequate stdout for post-UEFI, but the UEFI one is now invalid.
|
||||||
|
unsafe {
|
||||||
|
LOGGER_STDIO = LoggerStdio::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
main(st_runtime, mmap);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue