Skip to content

Commit 71145b2

Browse files
authored
Merge pull request #324 from hermit-os/uefi-output
feat: modularize console implementation for late UEFI output
2 parents dcaca37 + d9f1caf commit 71145b2

26 files changed

+821
-731
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88

99
[dependencies]
1010
align-address = "0.1"
11+
cfg-if = "1"
1112
hermit-entry = { version = "0.9", features = ["loader"] }
1213
log = "0.4"
1314
one-shot-mutex = "0.1"
@@ -38,7 +39,7 @@ spinning_top = "0.3"
3839

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

4445
[target.'cfg(target_arch = "riscv64")'.dependencies]

src/arch/aarch64/console.rs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use core::ptr::NonNull;
2+
3+
use hermit_dtb::Dtb;
4+
5+
pub struct Console {
6+
stdout: NonNull<u8>,
7+
}
8+
9+
fn stdout() -> u32 {
10+
/// Physical address of UART0 at Qemu's virt emulation
11+
const SERIAL_PORT_ADDRESS: u32 = 0x09000000;
12+
13+
let dtb = unsafe {
14+
Dtb::from_raw(sptr::from_exposed_addr(super::DEVICE_TREE as usize))
15+
.expect(".dtb file has invalid header")
16+
};
17+
18+
let property = dtb.get_property("/chosen", "stdout-path");
19+
let uart_address = if let Some(stdout) = property {
20+
let stdout = core::str::from_utf8(stdout)
21+
.unwrap()
22+
.trim_matches(char::from(0));
23+
if let Some(pos) = stdout.find('@') {
24+
let len = stdout.len();
25+
u32::from_str_radix(&stdout[pos + 1..len], 16).unwrap_or(SERIAL_PORT_ADDRESS)
26+
} else {
27+
SERIAL_PORT_ADDRESS
28+
}
29+
} else {
30+
SERIAL_PORT_ADDRESS
31+
};
32+
uart_address
33+
}
34+
35+
impl Console {
36+
pub fn write_bytes(&mut self, bytes: &[u8]) {
37+
for byte in bytes.iter().copied() {
38+
unsafe {
39+
self.stdout.as_ptr().write_volatile(byte);
40+
}
41+
}
42+
}
43+
44+
pub(super) fn get_stdout(&self) -> NonNull<u8> {
45+
self.stdout
46+
}
47+
48+
pub(super) fn set_stdout(&mut self, stdout: NonNull<u8>) {
49+
self.stdout = stdout;
50+
}
51+
}
52+
53+
impl Default for Console {
54+
fn default() -> Self {
55+
let stdout = NonNull::new(stdout() as *mut u8).unwrap();
56+
Self { stdout }
57+
}
58+
}
59+
60+
unsafe impl Send for Console {}

src/arch/aarch64/mod.rs

+9-44
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
mod console;
2+
pub use self::console::Console;
13
pub mod entry;
24
pub mod paging;
3-
pub mod serial;
45

56
use core::arch::asm;
6-
use core::ptr;
7+
use core::ptr::{self, NonNull};
78

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

1718
use crate::arch::paging::*;
18-
use crate::arch::serial::SerialPort;
19+
use crate::os::CONSOLE;
1920

2021
extern "C" {
2122
static loader_end: u8;
@@ -29,8 +30,6 @@ extern "C" {
2930

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

48-
// VARIABLES
49-
static mut COM1: SerialPort = SerialPort::new(SERIAL_PORT_ADDRESS);
50-
51-
pub fn message_output_init() {
52-
let dtb = unsafe {
53-
Dtb::from_raw(sptr::from_exposed_addr(DEVICE_TREE as usize))
54-
.expect(".dtb file has invalid header")
55-
};
56-
57-
let property = dtb.get_property("/chosen", "stdout-path");
58-
let uart_address = if let Some(stdout) = property {
59-
let stdout = core::str::from_utf8(stdout)
60-
.unwrap()
61-
.trim_matches(char::from(0));
62-
if let Some(pos) = stdout.find('@') {
63-
let len = stdout.len();
64-
u32::from_str_radix(&stdout[pos + 1..len], 16).unwrap_or(SERIAL_PORT_ADDRESS)
65-
} else {
66-
SERIAL_PORT_ADDRESS
67-
}
68-
} else {
69-
SERIAL_PORT_ADDRESS
70-
};
71-
72-
unsafe {
73-
COM1.set_port(uart_address);
74-
}
75-
}
76-
77-
pub fn output_message_byte(byte: u8) {
78-
unsafe {
79-
COM1.write_byte(byte);
80-
}
81-
}
82-
8347
pub unsafe fn get_memory(_memory_size: u64) -> u64 {
8448
(unsafe { ptr::addr_of!(loader_end) }.addr() as u64).align_up(LargePageSize::SIZE as u64)
8549
}
@@ -152,7 +116,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
152116
.count();
153117
info!("Detect {} CPU(s)", cpus);
154118

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

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

201-
unsafe {
202-
COM1.set_port(0x1000);
203-
}
165+
CONSOLE
166+
.lock()
167+
.get()
168+
.set_stdout(NonNull::new(0x1000 as *mut u8).unwrap());
204169

205170
// Load TTBRx
206171
unsafe {

src/arch/aarch64/serial.rs

-33
Original file line numberDiff line numberDiff line change
@@ -1,33 +0,0 @@
1-
pub struct SerialPort {
2-
port_address: u32,
3-
}
4-
5-
impl SerialPort {
6-
pub const fn new(port_address: u32) -> Self {
7-
Self { port_address }
8-
}
9-
10-
pub unsafe fn set_port(&mut self, addr: u32) {
11-
unsafe {
12-
core::ptr::write_volatile(&mut self.port_address, addr);
13-
}
14-
}
15-
16-
pub unsafe fn get_port(&self) -> u32 {
17-
unsafe { core::ptr::read_volatile(&self.port_address) }
18-
}
19-
20-
pub fn write_byte(&self, byte: u8) {
21-
unsafe {
22-
let port =
23-
sptr::from_exposed_addr_mut(core::ptr::read_volatile(&self.port_address) as usize);
24-
25-
// LF newline characters need to be extended to CRLF over a real serial port.
26-
if byte == b'\n' {
27-
core::ptr::write_volatile(port, b'\r');
28-
}
29-
30-
core::ptr::write_volatile(port, byte);
31-
}
32-
}
33-
}

src/arch/mod.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
#[cfg(target_arch = "aarch64")]
2-
pub use crate::arch::aarch64::*;
3-
#[cfg(target_arch = "riscv64")]
4-
pub use crate::arch::riscv64::*;
5-
#[cfg(all(target_arch = "x86_64", target_os = "none"))]
6-
pub use crate::arch::x86_64::*;
7-
8-
#[cfg(target_arch = "aarch64")]
9-
pub mod aarch64;
10-
11-
#[cfg(target_arch = "riscv64")]
12-
pub mod riscv64;
13-
14-
#[cfg(all(target_arch = "x86_64", target_os = "none"))]
15-
pub mod x86_64;
1+
cfg_if::cfg_if! {
2+
if #[cfg(target_arch = "aarch64")] {
3+
mod aarch64;
4+
pub use self::aarch64::*;
5+
} else if #[cfg(target_arch = "riscv64")] {
6+
mod riscv64;
7+
pub use self::riscv64::*;
8+
} else if #[cfg(all(target_arch = "x86_64"))] {
9+
mod x86_64;
10+
pub use self::x86_64::*;
11+
}
12+
}

src/arch/riscv64/console.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use sbi_rt::Physical;
2+
use sptr::Strict;
3+
4+
#[derive(Default)]
5+
pub struct Console(());
6+
7+
impl Console {
8+
pub fn write_bytes(&mut self, bytes: &[u8]) {
9+
sbi_rt::console_write(Physical::new(bytes.len(), bytes.as_ptr().addr(), 0));
10+
}
11+
}

src/arch/riscv64/mod.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod console;
2+
pub use self::console::Console;
13
mod address_range;
24
mod start;
35

@@ -14,10 +16,6 @@ use hermit_entry::Entry;
1416
use log::info;
1517
use sptr::Strict;
1618

17-
pub fn message_output_init() {}
18-
19-
pub use sbi_rt::console_write_byte as output_message_byte;
20-
2119
fn find_kernel_linux(chosen: &FdtNode<'_, '_>) -> Option<&'static [u8]> {
2220
let initrd_start = chosen.property("linux,initrd-start")?.as_usize()?;
2321
let initrd_start = sptr::from_exposed_addr_mut::<u8>(initrd_start);

src/arch/riscv64/start.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" fn start(hart_id: usize, fdt: *const u8) -> ! {
5252
HART_ID.store(hart_id, Ordering::Relaxed);
5353
FDT.store(fdt.cast_mut(), Ordering::Relaxed);
5454

55-
unsafe { crate::none::loader_main() }
55+
unsafe { crate::os::loader_main() }
5656
}
5757

5858
// Align to page size

src/arch/x86_64/console.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use uart_16550::SerialPort;
2+
3+
pub struct Console {
4+
serial_port: SerialPort,
5+
}
6+
7+
impl Console {
8+
pub fn write_bytes(&mut self, bytes: &[u8]) {
9+
for byte in bytes.iter().copied() {
10+
self.serial_port.send(byte);
11+
}
12+
}
13+
}
14+
15+
impl Default for Console {
16+
fn default() -> Self {
17+
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
18+
serial_port.init();
19+
Self { serial_port }
20+
}
21+
}

src/arch/x86_64/fdt.rs

-50
This file was deleted.

0 commit comments

Comments
 (0)