Skip to content

Commit

Permalink
feat: rework arch-specific console abstraction
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Kröning <[email protected]>
  • Loading branch information
mkroening committed Apr 9, 2024
1 parent 28d172d commit 2164b54
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 105 deletions.
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 {}
55 changes: 9 additions & 46 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 kernel_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,43 +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 write_to_console(bytes: &[u8]) {
for byte in bytes.iter().copied() {
unsafe {
COM1.write_byte(byte);
}
}
}

pub unsafe fn get_memory(_memory_size: u64) -> u64 {
(unsafe { ptr::addr_of!(kernel_end) }.addr() as u64).align_up(LargePageSize::SIZE as u64)
}
Expand Down Expand Up @@ -154,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 @@ -200,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);
}
}
}
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));
}
}
9 changes: 2 additions & 7 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 @@ -12,15 +14,8 @@ use hermit_entry::boot_info::{
use hermit_entry::elf::LoadedKernel;
use hermit_entry::Entry;
use log::info;
use sbi_rt::Physical;
use sptr::Strict;

pub fn message_output_init() {}

pub fn write_to_console(bytes: &[u8]) {
sbi_rt::console_write(Physical::new(bytes.len(), bytes.as_ptr().addr(), 0));
}

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
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 }
}
}
17 changes: 2 additions & 15 deletions src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
mod console;
#[cfg(all(target_os = "none", not(feature = "fc")))]
mod fdt;
mod paging;
pub use console::Console;
mod physicalmem;

use core::arch::asm;
Expand Down Expand Up @@ -30,7 +32,6 @@ use multiboot::information::MemoryManagement;
#[cfg(all(target_os = "none", not(feature = "fc")))]
use multiboot::information::{Multiboot, PAddr};
use sptr::Strict;
use uart_16550::SerialPort;
use x86_64::structures::paging::{PageSize, PageTableFlags, Size2MiB, Size4KiB};

#[cfg(all(target_os = "none", not(feature = "fc")))]
Expand All @@ -50,9 +51,6 @@ extern "C" {
const KERNEL_STACK_SIZE: u64 = 32_768;
const SERIAL_IO_PORT: u16 = 0x3F8;

// VARIABLES
static mut COM1: SerialPort = unsafe { SerialPort::new(SERIAL_IO_PORT) };

#[cfg(all(target_os = "none", not(feature = "fc")))]
struct Mem;

Expand Down Expand Up @@ -84,17 +82,6 @@ mod entry {
core::arch::global_asm!(include_str!("entry_fc.s"));
}

// FUNCTIONS
pub fn message_output_init() {
unsafe { COM1.init() };
}

pub fn write_to_console(bytes: &[u8]) {
for byte in bytes.iter().copied() {
unsafe { COM1.send(byte) };
}
}

#[cfg(all(target_os = "none", feature = "fc"))]
pub fn find_kernel() -> &'static [u8] {
use core::cmp;
Expand Down
23 changes: 20 additions & 3 deletions src/os/none/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,30 @@ use core::fmt;

use one_shot_mutex::OneShotMutex;

pub struct Console(());
use crate::arch;

pub struct Console {
console: Option<arch::Console>,
}

impl Console {
const fn new() -> Self {
Self { console: None }
}

#[cfg(target_arch = "aarch64")]
pub fn get(&mut self) -> &mut arch::Console {
self.console.get_or_insert_with(arch::Console::default)
}
}

impl fmt::Write for Console {
fn write_str(&mut self, s: &str) -> fmt::Result {
crate::arch::write_to_console(s.as_bytes());
self.console
.get_or_insert_with(arch::Console::default)
.write_bytes(s.as_bytes());
Ok(())
}
}

pub static CONSOLE: OneShotMutex<Console> = OneShotMutex::new(Console(()));
pub static CONSOLE: OneShotMutex<Console> = OneShotMutex::new(Console::new());
1 change: 0 additions & 1 deletion src/os/none/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ extern "C" {
/// (called from entry.asm or entry.rs)
#[no_mangle]
pub(crate) unsafe extern "C" fn loader_main() -> ! {
arch::message_output_init();
crate::log::init();

unsafe {
Expand Down

0 comments on commit 2164b54

Please sign in to comment.