mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
Revise console implementation in EFI stub
This commit is contained in:
@ -1,27 +1,23 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! A serial console.
|
||||||
|
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
use uart_16550::SerialPort;
|
use uart_16550::SerialPort;
|
||||||
|
|
||||||
|
use crate::sync::Mutex;
|
||||||
|
|
||||||
struct Stdout {
|
struct Stdout {
|
||||||
serial_port: SerialPort,
|
serial_port: SerialPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut STDOUT: Stdout = Stdout {
|
|
||||||
serial_port: unsafe { SerialPort::new(0x0) },
|
|
||||||
};
|
|
||||||
|
|
||||||
/// SAFETY: this function must only be called once
|
|
||||||
pub unsafe fn init() {
|
|
||||||
STDOUT = Stdout::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stdout {
|
impl Stdout {
|
||||||
/// SAFETY: this function must only be called once
|
fn new() -> Self {
|
||||||
pub unsafe fn init() -> Self {
|
// FIXME: Is it safe to assume that the serial port always exists?
|
||||||
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
|
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
|
||||||
serial_port.init();
|
serial_port.init();
|
||||||
|
|
||||||
Self { serial_port }
|
Self { serial_port }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,76 +29,28 @@ impl Write for Stdout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a string to the console.
|
static STDOUT: Mutex<Option<Stdout>> = Mutex::new(None);
|
||||||
///
|
|
||||||
/// This is used when dyn Trait is not supported or fmt::Arguments is fragile to use in PIE.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// [`init()`] must be called before it and there should be no race conditions.
|
|
||||||
pub unsafe fn print_str(s: &str) {
|
|
||||||
#[expect(static_mut_refs)]
|
|
||||||
STDOUT.write_str(s).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print a single character to the console.
|
/// Prints a format string and its arguments to the standard output.
|
||||||
///
|
pub fn print_fmt(args: fmt::Arguments) {
|
||||||
/// This is used when dyn Trait is not supported or fmt::Arguments is fragile to use in PIE.
|
let mut stdout = STDOUT.lock();
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// [`init()`] must be called before it and there should be no race conditions.
|
|
||||||
unsafe fn print_char(c: char) {
|
|
||||||
#[expect(static_mut_refs)]
|
|
||||||
STDOUT.serial_port.send(c as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print a hexadecimal number to the console.
|
// Fast path: The standard output has been initialized.
|
||||||
///
|
if let Some(inner) = stdout.as_mut() {
|
||||||
/// This is used when dyn Trait is not supported or fmt::Arguments is fragile to use in PIE.
|
inner.write_fmt(args).unwrap();
|
||||||
///
|
return;
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// [`init()`] must be called before it and there should be no race conditions.
|
|
||||||
pub unsafe fn print_hex(n: u64) {
|
|
||||||
print_str("0x");
|
|
||||||
for i in (0..16).rev() {
|
|
||||||
let digit = (n >> (i * 4)) & 0xf;
|
|
||||||
if digit < 10 {
|
|
||||||
print_char((b'0' + digit as u8) as char);
|
|
||||||
} else {
|
|
||||||
print_char((b'A' + (digit - 10) as u8) as char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Figure out why fmt::Arguments wont work even if relocations are applied.
|
|
||||||
// We just settle on simple print functions for now.
|
|
||||||
/*--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Glue code for print!() and println!() macros.
|
|
||||||
///
|
|
||||||
/// SAFETY: init() must be called before print_fmt() and there should be no race conditions.
|
|
||||||
pub unsafe fn print_fmt(args: fmt::Arguments) {
|
|
||||||
STDOUT.write_fmt(args).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
|
||||||
unsafe {
|
|
||||||
$crate::console::print_fmt(format_args!($fmt $(, $($arg)+)?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the standard output and print the string.
|
||||||
|
let mut inner = Stdout::new();
|
||||||
|
inner.write_fmt(args).unwrap();
|
||||||
|
*stdout = Some(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints to the standard output, with a newline.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
($fmt:literal $($arg:tt)*) => {
|
||||||
unsafe {
|
$crate::console::print_fmt(format_args!(concat!($fmt, "\n") $($arg)*))
|
||||||
$crate::console::print_fmt(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*------------------------------------------------------------------------------------------------*/
|
|
||||||
|
@ -26,20 +26,12 @@ fn load_segment(file: &xmas_elf::ElfFile, program: &xmas_elf::program::ProgramHe
|
|||||||
let dst_slice = unsafe {
|
let dst_slice = unsafe {
|
||||||
core::slice::from_raw_parts_mut(program.physical_addr as *mut u8, program.mem_size as usize)
|
core::slice::from_raw_parts_mut(program.physical_addr as *mut u8, program.mem_size as usize)
|
||||||
};
|
};
|
||||||
/* crate::println!(
|
#[cfg(feature = "debug_print")]
|
||||||
"[setup loader debug] loading ELF segment at {:#x}, size = {:#x}",
|
crate::println!(
|
||||||
|
"[setup] Loading an ELF segment: addr={:#x}, size={:#x}",
|
||||||
program.physical_addr,
|
program.physical_addr,
|
||||||
program.mem_size,
|
program.mem_size,
|
||||||
); */
|
);
|
||||||
#[cfg(feature = "debug_print")]
|
|
||||||
unsafe {
|
|
||||||
use crate::console::{print_hex, print_str};
|
|
||||||
print_str("[setup loader debug] loading ELF segment at ");
|
|
||||||
print_hex(program.physical_addr as u64);
|
|
||||||
print_str(", size = ");
|
|
||||||
print_hex(program.mem_size as u64);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
// SAFETY: the ELF file is valid
|
// SAFETY: the ELF file is valid
|
||||||
// dst_slice[..program.file_size as usize].copy_from_slice(header_data);
|
// dst_slice[..program.file_size as usize].copy_from_slice(header_data);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
mod console;
|
mod console;
|
||||||
mod loader;
|
mod loader;
|
||||||
|
mod sync;
|
||||||
|
|
||||||
// The entry points are defined in `x86/*/setup.S`.
|
// The entry points are defined in `x86/*/setup.S`.
|
||||||
mod x86;
|
mod x86;
|
||||||
|
27
ostd/libs/linux-bzimage/setup/src/sync.rs
Normal file
27
ostd/libs/linux-bzimage/setup/src/sync.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Synchronization primitives.
|
||||||
|
|
||||||
|
use core::cell::{RefCell, RefMut};
|
||||||
|
|
||||||
|
/// A mutex.
|
||||||
|
pub struct Mutex<T>(RefCell<T>);
|
||||||
|
|
||||||
|
// SAFETY: We're single-threaded.
|
||||||
|
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||||
|
unsafe impl<T: Sync> Sync for Mutex<T> {}
|
||||||
|
|
||||||
|
/// A mutex guard.
|
||||||
|
type MutexGuard<'a, T> = RefMut<'a, T>;
|
||||||
|
|
||||||
|
impl<T> Mutex<T> {
|
||||||
|
/// Creates a new mutex.
|
||||||
|
pub const fn new(data: T) -> Self {
|
||||||
|
Self(RefCell::new(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Locks the mutex.
|
||||||
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
|
self.0.borrow_mut()
|
||||||
|
}
|
||||||
|
}
|
@ -37,12 +37,6 @@ extern "sysv64" fn main_efi_handover64(
|
|||||||
/// This function should be called only once with valid parameters before all
|
/// This function should be called only once with valid parameters before all
|
||||||
/// operations.
|
/// operations.
|
||||||
unsafe fn system_init(handle: Handle, system_table: *const SystemTable) {
|
unsafe fn system_init(handle: Handle, system_table: *const SystemTable) {
|
||||||
// SAFETY: This is the right time to initialize the console and it is only
|
|
||||||
// called once here before all console operations.
|
|
||||||
unsafe {
|
|
||||||
crate::console::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: The handle and system_table are valid pointers. They are passed
|
// SAFETY: The handle and system_table are valid pointers. They are passed
|
||||||
// from the UEFI firmware. They are only called once.
|
// from the UEFI firmware. They are only called once.
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -53,8 +47,8 @@ unsafe fn system_init(handle: Handle, system_table: *const SystemTable) {
|
|||||||
|
|
||||||
fn efi_phase_boot(boot_params: &mut BootParams) -> ! {
|
fn efi_phase_boot(boot_params: &mut BootParams) -> ! {
|
||||||
uefi::println!(
|
uefi::println!(
|
||||||
"[EFI stub] Stub loaded at {:#x?}",
|
"[EFI stub] Loaded with offset {:#x}",
|
||||||
crate::x86::image_load_offset()
|
crate::x86::image_load_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fill the boot params with the RSDP address if it is not provided.
|
// Fill the boot params with the RSDP address if it is not provided.
|
||||||
@ -65,10 +59,10 @@ fn efi_phase_boot(boot_params: &mut BootParams) -> ! {
|
|||||||
// Load the kernel payload to memory.
|
// Load the kernel payload to memory.
|
||||||
let kernel = decode_payload(crate::x86::payload());
|
let kernel = decode_payload(crate::x86::payload());
|
||||||
|
|
||||||
uefi::println!("[EFI stub] Loading payload.");
|
uefi::println!("[EFI stub] Loading the payload as an ELF file");
|
||||||
crate::loader::load_elf(&kernel);
|
crate::loader::load_elf(&kernel);
|
||||||
|
|
||||||
uefi::println!("[EFI stub] Exiting EFI boot services.");
|
uefi::println!("[EFI stub] Exiting EFI boot services");
|
||||||
let memory_type = {
|
let memory_type = {
|
||||||
let Ok(loaded_image) = open_protocol_exclusive::<LoadedImage>(boot::image_handle()) else {
|
let Ok(loaded_image) = open_protocol_exclusive::<LoadedImage>(boot::image_handle()) else {
|
||||||
panic!("Failed to open LoadedImage protocol");
|
panic!("Failed to open LoadedImage protocol");
|
||||||
@ -83,27 +77,21 @@ fn efi_phase_boot(boot_params: &mut BootParams) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn efi_phase_runtime(memory_map: MemoryMapOwned, boot_params: &mut BootParams) -> ! {
|
fn efi_phase_runtime(memory_map: MemoryMapOwned, boot_params: &mut BootParams) -> ! {
|
||||||
unsafe {
|
crate::println!(
|
||||||
crate::console::print_str("[EFI stub] Entered runtime services.\n");
|
"[EFI stub] Processing {} memory map entries",
|
||||||
}
|
memory_map.entries().len()
|
||||||
|
);
|
||||||
#[cfg(feature = "debug_print")]
|
#[cfg(feature = "debug_print")]
|
||||||
unsafe {
|
{
|
||||||
use crate::console::{print_hex, print_str};
|
memory_map.entries().for_each(|entry| {
|
||||||
print_str("[EFI stub debug] EFI Memory map:\n");
|
crate::println!(
|
||||||
for md in memory_map.entries() {
|
" [{:#x}] {:#x} (size={:#x}) {{flags={:#x}}}",
|
||||||
// crate::println!(" [{:#x}] {:#x} ({:#x})", md.ty.0, md.phys_start, md.page_count);
|
entry.ty.0,
|
||||||
print_str(" [");
|
entry.phys_start,
|
||||||
print_hex(md.ty.0 as u64);
|
entry.page_count,
|
||||||
print_str("]");
|
entry.att.bits()
|
||||||
print_hex(md.phys_start);
|
);
|
||||||
print_str("(size=");
|
})
|
||||||
print_hex(md.page_count);
|
|
||||||
print_str(")");
|
|
||||||
print_str("{flags=");
|
|
||||||
print_hex(md.att.bits());
|
|
||||||
print_str("}\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write memory map to e820 table in boot_params.
|
// Write memory map to e820 table in boot_params.
|
||||||
@ -111,11 +99,7 @@ fn efi_phase_runtime(memory_map: MemoryMapOwned, boot_params: &mut BootParams) -
|
|||||||
let mut e820_entries = 0usize;
|
let mut e820_entries = 0usize;
|
||||||
for md in memory_map.entries() {
|
for md in memory_map.entries() {
|
||||||
if e820_entries >= e820_table.len() || e820_entries >= 127 {
|
if e820_entries >= e820_table.len() || e820_entries >= 127 {
|
||||||
unsafe {
|
crate::println!("[EFI stub] Warning: The number of E820 entries exceeded 128!");
|
||||||
crate::console::print_str(
|
|
||||||
"[EFI stub] Warning: number of E820 entries exceeded 128!\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
e820_table[e820_entries] = linux_boot_params::BootE820Entry {
|
||||||
@ -131,7 +115,7 @@ fn efi_phase_runtime(memory_map: MemoryMapOwned, boot_params: &mut BootParams) -
|
|||||||
#[cfg(feature = "cvm_guest")]
|
#[cfg(feature = "cvm_guest")]
|
||||||
uefi::table::boot::MemoryType::UNACCEPTED => {
|
uefi::table::boot::MemoryType::UNACCEPTED => {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::console::print_str("[EFI stub] Accepting pending pages...\n");
|
crate::println!("[EFI stub] Accepting pending pages");
|
||||||
for page_idx in 0..md.page_count {
|
for page_idx in 0..md.page_count {
|
||||||
tdx_guest::tdcall::accept_page(0, md.phys_start + page_idx * PAGE_SIZE)
|
tdx_guest::tdcall::accept_page(0, md.phys_start + page_idx * PAGE_SIZE)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -146,13 +130,10 @@ fn efi_phase_runtime(memory_map: MemoryMapOwned, boot_params: &mut BootParams) -
|
|||||||
}
|
}
|
||||||
boot_params.e820_entries = e820_entries as u8;
|
boot_params.e820_entries = e820_entries as u8;
|
||||||
|
|
||||||
unsafe {
|
crate::println!(
|
||||||
use crate::console::{print_hex, print_str};
|
"[EFI stub] Entering the Asterinas entry point at {:#x}",
|
||||||
print_str("[EFI stub] Entering Asterinas entrypoint at ");
|
super::ASTER_ENTRY_POINT,
|
||||||
print_hex(super::ASTER_ENTRY_POINT as u64);
|
);
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
super::call_aster_entrypoint(
|
super::call_aster_entrypoint(
|
||||||
super::ASTER_ENTRY_POINT as u64,
|
super::ASTER_ENTRY_POINT as u64,
|
||||||
|
@ -4,24 +4,22 @@ use core::arch::{asm, global_asm};
|
|||||||
|
|
||||||
global_asm!(include_str!("setup.S"));
|
global_asm!(include_str!("setup.S"));
|
||||||
|
|
||||||
use crate::console::{print_hex, print_str};
|
|
||||||
|
|
||||||
pub const ASTER_ENTRY_POINT: u32 = 0x8001000;
|
pub const ASTER_ENTRY_POINT: u32 = 0x8001000;
|
||||||
|
|
||||||
#[export_name = "main_legacy32"]
|
#[export_name = "main_legacy32"]
|
||||||
extern "cdecl" fn main_legacy32(boot_params_ptr: u32) -> ! {
|
extern "cdecl" fn main_legacy32(boot_params_ptr: u32) -> ! {
|
||||||
// SAFETY: this init function is only called once.
|
crate::println!(
|
||||||
unsafe { crate::console::init() };
|
"[setup] Loaded with offset {:#x}",
|
||||||
|
crate::x86::image_load_offset(),
|
||||||
// println!("[setup] bzImage loaded at {:#x}", x86::relocation::image_load_offset());
|
);
|
||||||
unsafe {
|
|
||||||
print_str("[setup] bzImage loaded offset: ");
|
|
||||||
print_hex(crate::x86::image_load_offset() as u64);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
crate::println!("[setup] Loading the payload as an ELF file");
|
||||||
crate::loader::load_elf(crate::x86::payload());
|
crate::loader::load_elf(crate::x86::payload());
|
||||||
|
|
||||||
|
crate::println!(
|
||||||
|
"[setup] Entering the Asterinas entry point at {:#x}",
|
||||||
|
ASTER_ENTRY_POINT,
|
||||||
|
);
|
||||||
// SAFETY: the entrypoint and the ptr is valid.
|
// SAFETY: the entrypoint and the ptr is valid.
|
||||||
unsafe { call_aster_entrypoint(ASTER_ENTRY_POINT, boot_params_ptr.try_into().unwrap()) };
|
unsafe { call_aster_entrypoint(ASTER_ENTRY_POINT, boot_params_ptr.try_into().unwrap()) };
|
||||||
}
|
}
|
||||||
@ -35,6 +33,11 @@ unsafe fn call_aster_entrypoint(entrypoint: u32, boot_params_ptr: u32) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
loop {}
|
crate::println!("[PANIC]: {}", info);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// SAFETY: `hlt` has no effect other than to stop the CPU and wait for another interrupt.
|
||||||
|
unsafe { asm!("hlt", options(nomem, nostack, preserves_flags)) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user