#![no_std]
#![feature(alloc_error_handler)]
#![feature(asm)]
#![feature(lang_items)]
#![feature(panic_info_message)]
extern crate rlibc;
extern crate uefi;
#[macro_use]
extern crate log;
use core::ptr::NonNull;
use uefi::prelude::*;
use uefi::table::boot::{EventType, Tpl};
use uefi::table::{Boot, SystemTable};
use uefi::{Event, Result};
static mut SYSTEM_TABLE: Option<SystemTable<Boot>> = None;
static mut LOGGER: Option<uefi::logger::Logger> = None;
pub fn system_table() -> NonNull<SystemTable<Boot>> {
unsafe {
let table_ref = SYSTEM_TABLE
.as_ref()
.expect("The system table handle is not available");
NonNull::new(table_ref as *const _ as *mut _).unwrap()
}
}
pub fn init(st: &SystemTable<Boot>) -> Result {
unsafe {
if SYSTEM_TABLE.is_some() {
return Status::SUCCESS.into();
}
SYSTEM_TABLE = Some(st.unsafe_clone());
let boot_services = st.boot_services();
init_logger(st);
uefi::alloc::init(boot_services);
boot_services
.create_event(
EventType::SIGNAL_EXIT_BOOT_SERVICES,
Tpl::NOTIFY,
Some(exit_boot_services),
)
.map_inner(|_| ())
}
}
unsafe fn init_logger(st: &SystemTable<Boot>) {
let stdout = st.stdout();
let logger = {
LOGGER = Some(uefi::logger::Logger::new(stdout));
LOGGER.as_ref().unwrap()
};
log::set_logger(logger).unwrap();
log::set_max_level(log::LevelFilter::Info);
}
fn exit_boot_services(_e: Event) {
unsafe {
SYSTEM_TABLE = None;
if let Some(ref mut logger) = LOGGER {
logger.disable();
}
}
uefi::alloc::exit_boot_services();
}
#[lang = "eh_personality"]
fn eh_personality() {}
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
if let Some(location) = info.location() {
error!(
"Panic in {} at ({}, {}):",
location.file(),
location.line(),
location.column()
);
if let Some(message) = info.message() {
error!("{}", message);
}
}
if let Some(st) = unsafe { SYSTEM_TABLE.as_ref() } {
st.boot_services().stall(10_000_000);
} else {
let mut dummy = 0u64;
for i in 0..300_000_000 {
unsafe {
core::ptr::write_volatile(&mut dummy, i);
}
}
}
if cfg!(feature = "qemu") {
use x86_64::instructions::port::Port;
let mut port = Port::<u32>::new(0xf4);
unsafe {
port.write(42);
}
}
if let Some(st) = unsafe { SYSTEM_TABLE.as_ref() } {
use uefi::table::runtime::ResetType;
st.runtime_services()
.reset(ResetType::Shutdown, uefi::Status::ABORTED, None);
}
error!("Could not shut down, please power off the system manually...");
loop {
unsafe {
asm!("hlt" :::: "volatile");
}
}
}
#[alloc_error_handler]
fn out_of_memory(layout: ::core::alloc::Layout) -> ! {
panic!(
"Ran out of free memory while trying to allocate {:#?}",
layout
);
}