Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: modularize console implementation for late UEFI output #324

Merged
merged 13 commits into from
Apr 9, 2024
Merged
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"

[dependencies]
align-address = "0.1"
cfg-if = "1"
hermit-entry = { version = "0.9", features = ["loader"] }
log = "0.4"
one-shot-mutex = "0.1"
Expand Down Expand Up @@ -38,7 +39,7 @@ spinning_top = "0.3"

[target.'cfg(target_os = "uefi")'.dependencies]
uefi = { version = "0.27", features = ["alloc"] }
uefi-services = { version = "0.24", features = ["qemu"] }
uefi-services = { version = "0.24", default-features = false, features = ["panic_handler", "qemu"] }
qemu-exit = "3"

[target.'cfg(target_arch = "riscv64")'.dependencies]
Expand Down
60 changes: 60 additions & 0 deletions src/arch/aarch64/console.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use core::ptr::NonNull;

use hermit_dtb::Dtb;

pub struct Console {
stdout: NonNull<u8>,
}

fn stdout() -> u32 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this fn name a little confusing. Maybe something like get_stdout or stdout_addr would be more self-explanatory. A doc-comment might also help.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. Though, just adding “get” does not help much, I think. I did not rework this code, I only moved it around.
I am planning a proper rework of this while migrating from hermit-dtb to fdt.

/// Physical address of UART0 at Qemu's virt emulation
const SERIAL_PORT_ADDRESS: u32 = 0x09000000;

let dtb = unsafe {
Dtb::from_raw(sptr::from_exposed_addr(super::DEVICE_TREE as usize))
.expect(".dtb file has invalid header")
};

let property = dtb.get_property("/chosen", "stdout-path");
let uart_address = if let Some(stdout) = property {
let stdout = core::str::from_utf8(stdout)
.unwrap()
.trim_matches(char::from(0));
if let Some(pos) = stdout.find('@') {
let len = stdout.len();
u32::from_str_radix(&stdout[pos + 1..len], 16).unwrap_or(SERIAL_PORT_ADDRESS)
} else {
SERIAL_PORT_ADDRESS
}
} else {
SERIAL_PORT_ADDRESS
};
uart_address
}

impl Console {
pub fn write_bytes(&mut self, bytes: &[u8]) {
for byte in bytes.iter().copied() {
unsafe {
self.stdout.as_ptr().write_volatile(byte);
}
}
}

pub(super) fn get_stdout(&self) -> NonNull<u8> {
self.stdout
}

pub(super) fn set_stdout(&mut self, stdout: NonNull<u8>) {
self.stdout = stdout;
}
}

impl Default for Console {
fn default() -> Self {
let stdout = NonNull::new(stdout() as *mut u8).unwrap();
Self { stdout }
}
}

unsafe impl Send for Console {}
53 changes: 9 additions & 44 deletions src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
mod console;
pub use self::console::Console;
pub mod entry;
pub mod paging;
pub mod serial;

use core::arch::asm;
use core::ptr;
use core::ptr::{self, NonNull};

use align_address::Align;
use goblin::elf::header::header64::{Header, EI_DATA, ELFDATA2LSB, ELFMAG, SELFMAG};
Expand All @@ -15,7 +16,7 @@ use log::info;
use sptr::Strict;

use crate::arch::paging::*;
use crate::arch::serial::SerialPort;
use crate::os::CONSOLE;

extern "C" {
static loader_end: u8;
Expand All @@ -29,8 +30,6 @@ extern "C" {

/// start address of the RAM at Qemu's virt emulation
const RAM_START: u64 = 0x40000000;
/// Physical address of UART0 at Qemu's virt emulation
const SERIAL_PORT_ADDRESS: u32 = 0x09000000;
/// Default stack size of the kernel
const KERNEL_STACK_SIZE: usize = 32_768;
/// Qemu assumes for ELF kernel that the DTB is located at
Expand All @@ -45,41 +44,6 @@ const PT_MEM: u64 = 0x713;
const PT_MEM_CD: u64 = 0x70F;
const PT_SELF: u64 = 1 << 55;

// VARIABLES
static mut COM1: SerialPort = SerialPort::new(SERIAL_PORT_ADDRESS);

pub fn message_output_init() {
let dtb = unsafe {
Dtb::from_raw(sptr::from_exposed_addr(DEVICE_TREE as usize))
.expect(".dtb file has invalid header")
};

let property = dtb.get_property("/chosen", "stdout-path");
let uart_address = if let Some(stdout) = property {
let stdout = core::str::from_utf8(stdout)
.unwrap()
.trim_matches(char::from(0));
if let Some(pos) = stdout.find('@') {
let len = stdout.len();
u32::from_str_radix(&stdout[pos + 1..len], 16).unwrap_or(SERIAL_PORT_ADDRESS)
} else {
SERIAL_PORT_ADDRESS
}
} else {
SERIAL_PORT_ADDRESS
};

unsafe {
COM1.set_port(uart_address);
}
}

pub fn output_message_byte(byte: u8) {
unsafe {
COM1.write_byte(byte);
}
}

pub unsafe fn get_memory(_memory_size: u64) -> u64 {
(unsafe { ptr::addr_of!(loader_end) }.addr() as u64).align_up(LargePageSize::SIZE as u64)
}
Expand Down Expand Up @@ -152,7 +116,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
.count();
info!("Detect {} CPU(s)", cpus);

let uart_address: u32 = unsafe { COM1.get_port() };
let uart_address: u32 = CONSOLE.lock().get().get_stdout().as_ptr() as u32;
info!("Detect UART at {:#x}", uart_address);

let pgt_slice = unsafe { core::slice::from_raw_parts_mut(ptr::addr_of_mut!(l0_pgtable), 512) };
Expand Down Expand Up @@ -198,9 +162,10 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
*entry = RAM_START + (i * BasePageSize::SIZE) as u64 + PT_MEM;
}

unsafe {
COM1.set_port(0x1000);
}
CONSOLE
.lock()
.get()
.set_stdout(NonNull::new(0x1000 as *mut u8).unwrap());

// Load TTBRx
unsafe {
Expand Down
33 changes: 0 additions & 33 deletions src/arch/aarch64/serial.rs
Original file line number Diff line number Diff line change
@@ -1,33 +0,0 @@
pub struct SerialPort {
port_address: u32,
}

impl SerialPort {
pub const fn new(port_address: u32) -> Self {
Self { port_address }
}

pub unsafe fn set_port(&mut self, addr: u32) {
unsafe {
core::ptr::write_volatile(&mut self.port_address, addr);
}
}

pub unsafe fn get_port(&self) -> u32 {
unsafe { core::ptr::read_volatile(&self.port_address) }
}

pub fn write_byte(&self, byte: u8) {
unsafe {
let port =
sptr::from_exposed_addr_mut(core::ptr::read_volatile(&self.port_address) as usize);

// LF newline characters need to be extended to CRLF over a real serial port.
if byte == b'\n' {
core::ptr::write_volatile(port, b'\r');
}

core::ptr::write_volatile(port, byte);
}
}
}
27 changes: 12 additions & 15 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
#[cfg(target_arch = "aarch64")]
pub use crate::arch::aarch64::*;
#[cfg(target_arch = "riscv64")]
pub use crate::arch::riscv64::*;
#[cfg(all(target_arch = "x86_64", target_os = "none"))]
pub use crate::arch::x86_64::*;

#[cfg(target_arch = "aarch64")]
pub mod aarch64;

#[cfg(target_arch = "riscv64")]
pub mod riscv64;

#[cfg(all(target_arch = "x86_64", target_os = "none"))]
pub mod x86_64;
cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::*;
} else if #[cfg(target_arch = "riscv64")] {
mod riscv64;
pub use self::riscv64::*;
} else if #[cfg(all(target_arch = "x86_64"))] {
mod x86_64;
pub use self::x86_64::*;
}
}
11 changes: 11 additions & 0 deletions src/arch/riscv64/console.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use sbi_rt::Physical;
use sptr::Strict;

#[derive(Default)]
pub struct Console(());

impl Console {
pub fn write_bytes(&mut self, bytes: &[u8]) {
sbi_rt::console_write(Physical::new(bytes.len(), bytes.as_ptr().addr(), 0));
}
}
6 changes: 2 additions & 4 deletions src/arch/riscv64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod console;
pub use self::console::Console;
mod address_range;
mod start;

Expand All @@ -14,10 +16,6 @@ use hermit_entry::Entry;
use log::info;
use sptr::Strict;

pub fn message_output_init() {}

pub use sbi_rt::console_write_byte as output_message_byte;

fn find_kernel_linux(chosen: &FdtNode<'_, '_>) -> Option<&'static [u8]> {
let initrd_start = chosen.property("linux,initrd-start")?.as_usize()?;
let initrd_start = sptr::from_exposed_addr_mut::<u8>(initrd_start);
Expand Down
2 changes: 1 addition & 1 deletion src/arch/riscv64/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extern "C" fn start(hart_id: usize, fdt: *const u8) -> ! {
HART_ID.store(hart_id, Ordering::Relaxed);
FDT.store(fdt.cast_mut(), Ordering::Relaxed);

unsafe { crate::none::loader_main() }
unsafe { crate::os::loader_main() }
}

// Align to page size
Expand Down
21 changes: 21 additions & 0 deletions src/arch/x86_64/console.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use uart_16550::SerialPort;

pub struct Console {
serial_port: SerialPort,
}

impl Console {
pub fn write_bytes(&mut self, bytes: &[u8]) {
for byte in bytes.iter().copied() {
self.serial_port.send(byte);
}
}
}

impl Default for Console {
fn default() -> Self {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Self { serial_port }
}
}
50 changes: 0 additions & 50 deletions src/arch/x86_64/fdt.rs

This file was deleted.

Loading