Skip to content

Commit

Permalink
refactor(console): centralize state
Browse files Browse the repository at this point in the history
  • Loading branch information
mkroening committed Dec 12, 2024
1 parent 976579b commit 67ff185
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 90 deletions.
67 changes: 35 additions & 32 deletions src/arch/aarch64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use core::arch::global_asm;
use core::str;
use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};

use hermit_sync::SpinMutex;
use memory_addresses::arch::aarch64::{PhysAddr, VirtAddr};

use crate::arch::aarch64::kernel::core_local::*;
Expand All @@ -25,7 +24,41 @@ use crate::env;

const SERIAL_PORT_BAUDRATE: u32 = 115_200;

static COM1: SpinMutex<SerialPort> = SpinMutex::new(SerialPort::new(0x800));
pub struct Console {
serial_port: SerialPort,
}

impl Console {
pub fn new() -> Self {
CoreLocal::install();

let base = env::boot_info()
.hardware_info
.serial_port_base
.map(|uartport| uartport.get())
.unwrap_or_default()
.try_into()
.unwrap();

let serial_port = SerialPort::new(base);

serial_port.init(SERIAL_PORT_BAUDRATE);

Self { serial_port }
}

pub fn write(&mut self, buf: &[u8]) {
for byte in buf {
self.serial_port.write_byte(*byte);
}
}
}

impl Default for Console {
fn default() -> Self {
Self::new()
}
}

/// `CPU_ONLINE` is the count of CPUs that finished initialization.
///
Expand Down Expand Up @@ -77,36 +110,6 @@ pub fn args() -> Option<&'static str> {
None
}

/// Earliest initialization function called by the Boot Processor.
pub fn message_output_init() {
CoreLocal::install();

let mut com1 = COM1.lock();

com1.port_address = env::boot_info()
.hardware_info
.serial_port_base
.map(|uartport| uartport.get())
.unwrap_or_default()
.try_into()
.unwrap();

// We can only initialize the serial port here, because VGA requires processor
// configuration first.
com1.init(SERIAL_PORT_BAUDRATE);
}

pub fn output_message_byte(byte: u8) {
// Output messages to the serial port.
COM1.lock().write_byte(byte);
}

pub fn output_message_buf(buf: &[u8]) {
for byte in buf {
output_message_byte(*byte);
}
}

/// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen.
#[cfg(target_os = "none")]
pub fn boot_processor_init() {
Expand Down
6 changes: 0 additions & 6 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ cfg_if::cfg_if! {
pub(crate) use self::aarch64::kernel::application_processor_init;
pub(crate) use self::aarch64::kernel::{
get_processor_count,
message_output_init,
output_message_buf,
};
pub use self::aarch64::mm::paging::{BasePageSize, PageSize};
} else if #[cfg(target_arch = "x86_64")] {
Expand All @@ -46,8 +44,6 @@ cfg_if::cfg_if! {
pub(crate) use self::x86_64::kernel::boot_processor_init;
pub(crate) use self::x86_64::kernel::{
get_processor_count,
message_output_init,
output_message_buf,
};
pub use self::x86_64::mm::paging::{BasePageSize, PageSize};
#[cfg(feature = "common-os")]
Expand All @@ -68,8 +64,6 @@ cfg_if::cfg_if! {
core_local,
get_processor_count,
interrupts,
message_output_init,
output_message_buf,
scheduler,
switch,
};
Expand Down
33 changes: 22 additions & 11 deletions src/arch/riscv64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ use crate::config::KERNEL_STACK_SIZE;
use crate::env;
use crate::init_cell::InitCell;

pub struct Console {}

impl Console {
pub fn new() -> Self {
CoreLocal::install();

Self {}
}

pub fn write(&mut self, buf: &[u8]) {
for byte in buf {
sbi_rt::console_write_byte(*byte);
}
}
}

impl Default for Console {
fn default() -> Self {
Self::new()
}
}

// Used to store information about available harts. The index of the hart in the vector
// represents its CpuId and does not need to match its hart_id
pub(crate) static HARTS_AVAILABLE: InitCell<Vec<usize>> = InitCell::new(Vec::new());
Expand Down Expand Up @@ -109,17 +131,6 @@ pub fn get_current_boot_id() -> u32 {
CURRENT_BOOT_ID.load(Ordering::Relaxed)
}

/// Earliest initialization function called by the Boot Processor.
pub fn message_output_init() {
CoreLocal::install();
}

pub fn output_message_buf(buf: &[u8]) {
for byte in buf {
sbi_rt::console_write_byte(*byte);
}
}

/// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen.
pub fn boot_processor_init() {
devicetree::init();
Expand Down
73 changes: 43 additions & 30 deletions src/arch/x86_64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use core::ptr;
use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};

use hermit_entry::boot_info::{PlatformInfo, RawBootInfo};
use hermit_sync::InterruptSpinMutex;
use memory_addresses::{PhysAddr, VirtAddr};
use x86::controlregs::{cr0, cr0_write, cr4, Cr0};

Expand Down Expand Up @@ -37,8 +36,49 @@ pub(crate) mod systemtime;
#[cfg(feature = "vga")]
mod vga;

/// Serial port to print kernel messages
pub(crate) static COM1: InterruptSpinMutex<Option<SerialPort>> = InterruptSpinMutex::new(None);
pub struct Console {
serial_port: SerialPort,
}

impl Console {
pub fn new() -> Self {
CoreLocal::install();

let base = env::boot_info()
.hardware_info
.serial_port_base
.unwrap()
.get();
let serial_port = unsafe { SerialPort::new(base) };
Self { serial_port }
}

pub fn write(&mut self, buf: &[u8]) {
self.serial_port.send(buf);

#[cfg(feature = "vga")]
for &byte in buf {
// vga::write_byte() checks if VGA support has been initialized,
// so we don't need any additional if clause around it.
vga::write_byte(byte);
}
}

pub fn buffer_input(&mut self) {
self.serial_port.buffer_input();
}

#[cfg(feature = "shell")]
pub fn read(&mut self) -> Option<u8> {
self.serial_port.read()
}
}

impl Default for Console {
fn default() -> Self {
Self::new()
}
}

pub fn get_ram_address() -> PhysAddr {
PhysAddr::new(env::boot_info().hardware_info.phys_addr_range.start)
Expand Down Expand Up @@ -106,33 +146,6 @@ pub fn args() -> Option<&'static str> {
}
}

// We can only initialize the serial port here, because VGA requires processor
// configuration first.
/// Earliest initialization function called by the Boot Processor.
pub fn message_output_init() {
CoreLocal::install();

let base = env::boot_info()
.hardware_info
.serial_port_base
.unwrap()
.get();
let serial_port = unsafe { SerialPort::new(base) };
*COM1.lock() = Some(serial_port);
}

pub fn output_message_buf(buf: &[u8]) {
// Output messages to the serial port and VGA screen in unikernel mode.
COM1.lock().as_mut().unwrap().send(buf);

#[cfg(feature = "vga")]
for &byte in buf {
// vga::write_byte() checks if VGA support has been initialized,
// so we don't need any additional if clause around it.
vga::write_byte(byte);
}
}

/// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen.
#[cfg(target_os = "none")]
pub fn boot_processor_init() {
Expand Down
4 changes: 2 additions & 2 deletions src/arch/x86_64/kernel/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use alloc::collections::VecDeque;

use x86_64::instructions::port::Port;

use crate::arch::x86_64::kernel::apic;
use crate::arch::x86_64::kernel::core_local::increment_irq_counter;
use crate::arch::x86_64::kernel::interrupts::{self, IDT};
use crate::arch::x86_64::kernel::{apic, COM1};

const SERIAL_IRQ: u8 = 36;

Expand Down Expand Up @@ -76,7 +76,7 @@ impl SerialPort {
}

extern "x86-interrupt" fn serial_interrupt(_stack_frame: crate::interrupts::ExceptionStackFrame) {
COM1.lock().as_mut().unwrap().buffer_input();
crate::console::CONSOLE.lock().0.buffer_input();
increment_irq_counter(SERIAL_IRQ);

apic::eoi();
Expand Down
18 changes: 10 additions & 8 deletions src/console.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
use core::fmt;

use hermit_sync::InterruptTicketMutex;
use hermit_sync::{InterruptTicketMutex, Lazy};

use crate::arch;

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

impl Console {
fn new() -> Self {
Self(arch::kernel::Console::new())
}

pub fn write(&mut self, buf: &[u8]) {
arch::output_message_buf(buf);
self.0.write(buf);
}

#[cfg(feature = "shell")]
pub fn read(&mut self) -> Option<u8> {
crate::arch::kernel::COM1
.lock()
.as_mut()
.map(|s| s.read())?
self.0.read()
}
}

Expand All @@ -34,7 +35,8 @@ impl fmt::Write for Console {
}
}

pub(crate) static CONSOLE: InterruptTicketMutex<Console> = InterruptTicketMutex::new(Console(()));
pub static CONSOLE: Lazy<InterruptTicketMutex<Console>> =
Lazy::new(|| InterruptTicketMutex::new(Console::new()));

#[doc(hidden)]
pub fn _print(args: fmt::Arguments<'_>) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ fn synch_all_cores() {
#[cfg(target_os = "none")]
fn boot_processor_main() -> ! {
// Initialize the kernel and hardware.
arch::message_output_init();
hermit_sync::Lazy::force(&console::CONSOLE);
unsafe {
logging::init();
}
Expand Down

0 comments on commit 67ff185

Please sign in to comment.