Skip to content

Commit

Permalink
Merge pull request #324 from hermit-os/uefi-output
Browse files Browse the repository at this point in the history
feat: modularize console implementation for late UEFI output
  • Loading branch information
mkroening authored Apr 9, 2024
2 parents dcaca37 + d9f1caf commit 71145b2
Show file tree
Hide file tree
Showing 26 changed files with 821 additions and 731 deletions.
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 {
/// 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

0 comments on commit 71145b2

Please sign in to comment.