mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: rewrite console init logic
This commit is contained in:
parent
284e12348d
commit
5032711022
@ -6,7 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["arch_riscv64", "board_virt", "log_color", "frame_freelist"]
|
default = ["arch_riscv64", "board_virt", "log_color"]
|
||||||
|
|
||||||
arch_riscv64 = []
|
arch_riscv64 = []
|
||||||
arch_riscv32 = []
|
arch_riscv32 = []
|
||||||
@ -16,9 +16,6 @@ board_virt = []
|
|||||||
|
|
||||||
log_color = []
|
log_color = []
|
||||||
|
|
||||||
frame_bitmap = []
|
|
||||||
frame_freelist = []
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.section .text.trap
|
.section .text.trap
|
||||||
|
|
||||||
.extern trap_handler
|
.extern kernel_trap_handler
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
.global trap_entry
|
.global trap_entry
|
||||||
@ -64,10 +64,10 @@ __trap_from_user:
|
|||||||
beqz t2, __trap_from_user_next
|
beqz t2, __trap_from_user_next
|
||||||
|
|
||||||
__trap_from_kernel_next:
|
__trap_from_kernel_next:
|
||||||
# goto trap_handler
|
# goto kernel_trap_handler
|
||||||
mv a0, sp
|
mv a0, sp
|
||||||
la ra, __trap_return
|
la ra, __trap_return
|
||||||
j trap_handler
|
j kernel_trap_handler
|
||||||
|
|
||||||
__trap_from_user_next:
|
__trap_from_user_next:
|
||||||
# we come from switch_to_user, which saved callee-saved registers
|
# we come from switch_to_user, which saved callee-saved registers
|
||||||
@ -87,7 +87,7 @@ __trap_from_user_next:
|
|||||||
LD_SP s10, 10
|
LD_SP s10, 10
|
||||||
LD_SP s11, 11
|
LD_SP s11, 11
|
||||||
LD_SP ra, 12
|
LD_SP ra, 12
|
||||||
LD_SP tp, 13 # hartid
|
LD_SP tp, 13 # TLS
|
||||||
addi sp, sp, 14*XLENB
|
addi sp, sp, 14*XLENB
|
||||||
# return from switch_to_user
|
# return from switch_to_user
|
||||||
ret
|
ret
|
||||||
@ -110,7 +110,7 @@ switch_to_user:
|
|||||||
SD_SP s10, 10
|
SD_SP s10, 10
|
||||||
SD_SP s11, 11
|
SD_SP s11, 11
|
||||||
SD_SP ra, 12
|
SD_SP ra, 12
|
||||||
SD_SP tp, 13 # not callee-saved, but used in kernel to save hartid
|
SD_SP tp, 13 # not callee-saved, but used in kernel to save TLS
|
||||||
|
|
||||||
# switch to user context
|
# switch to user context
|
||||||
mv t0, sp
|
mv t0, sp
|
||||||
|
32
kernel/src/arch/riscv/board/default/console.rs
Normal file
32
kernel/src/arch/riscv/board/default/console.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver};
|
||||||
|
|
||||||
|
pub struct EarlyConsole;
|
||||||
|
|
||||||
|
impl ConsoleDevice for EarlyConsole {
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
loop {
|
||||||
|
if let Some(ch) = self.try_read() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_read(&mut self) -> Option<u8> {
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
let ret = sbi_rt::console_read(sbi_rt::Physical::new(1, buf.as_mut_ptr() as _, 0));
|
||||||
|
ret.ok()
|
||||||
|
.and_then(|len| if len == 0 { None } else { Some(buf[0]) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, ch: u8) {
|
||||||
|
sbi_rt::console_write_byte(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_str(&mut self, s: &str) {
|
||||||
|
sbi_rt::console_write(sbi_rt::Physical::new(s.len(), s.as_ptr() as _, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_early_console() {
|
||||||
|
set_console(ConsoleDriver::EarlyConsole(EarlyConsole));
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
use crate::plat::io::{Printer, RawConsole, Reader};
|
|
||||||
|
|
||||||
impl Printer for RawConsole {
|
|
||||||
#[inline]
|
|
||||||
fn put_char(c: char) {
|
|
||||||
sbi_rt::console_write_byte(c as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn put_str(s: &str) {
|
|
||||||
sbi_rt::console_write(sbi_rt::Physical::new(s.len(), s.as_ptr() as _, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reader for RawConsole {
|
|
||||||
#[inline]
|
|
||||||
fn get_char() -> char {
|
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
loop {
|
|
||||||
let ret = sbi_rt::console_read(sbi_rt::Physical::new(1, buf.as_mut_ptr() as _, 0));
|
|
||||||
if let Some(len) = ret.ok()
|
|
||||||
&& len == 1
|
|
||||||
{
|
|
||||||
return buf[0] as char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
pub const BOOT_HART_ID: usize = 0;
|
|
||||||
pub const TIMER_TICKS: u64 = 100_000; // 100ms
|
pub const TIMER_TICKS: u64 = 100_000; // 100ms
|
||||||
|
|
||||||
mod io;
|
pub mod console;
|
||||||
mod lowlevel;
|
mod lowlevel;
|
||||||
|
21
kernel/src/arch/riscv/board/virt/console.rs
Normal file
21
kernel/src/arch/riscv/board/virt/console.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver};
|
||||||
|
|
||||||
|
pub struct EarlyConsole;
|
||||||
|
|
||||||
|
impl ConsoleDevice for EarlyConsole {
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
let uart = super::UART0_BASE as *mut u8;
|
||||||
|
let line_sts = super::UART0_LSR as *mut u8;
|
||||||
|
while unsafe { line_sts.read_volatile() } & 0x01 == 0 {}
|
||||||
|
unsafe { uart.read_volatile() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, ch: u8) {
|
||||||
|
let uart = super::UART0_BASE as *mut u8;
|
||||||
|
unsafe { uart.write_volatile(ch) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_early_console() {
|
||||||
|
set_console(ConsoleDriver::EarlyConsole(EarlyConsole));
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
pub const BOOT_HART_ID: usize = 0;
|
|
||||||
pub const TIMER_TICKS: u64 = 100_000; // 100ms
|
pub const TIMER_TICKS: u64 = 100_000; // 100ms
|
||||||
|
|
||||||
// devices
|
// devices
|
||||||
@ -6,6 +5,5 @@ pub const UART0_BASE: usize = 0x1000_0000;
|
|||||||
pub const UART0_LSR: usize = 0x1000_0005;
|
pub const UART0_LSR: usize = 0x1000_0005;
|
||||||
pub const TEST_DEVICE: *mut u32 = 0x10_0000 as *mut u32;
|
pub const TEST_DEVICE: *mut u32 = 0x10_0000 as *mut u32;
|
||||||
|
|
||||||
|
pub mod console;
|
||||||
mod lowlevel;
|
mod lowlevel;
|
||||||
mod printer;
|
|
||||||
mod reader;
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
use crate::plat::io::{Printer, RawConsole};
|
|
||||||
|
|
||||||
// Theoretically, we should wait until "THR Empty" bit (1<<5 in LSR) is set before writing to UART.
|
|
||||||
|
|
||||||
impl Printer for RawConsole {
|
|
||||||
#[inline]
|
|
||||||
fn put_char(c: char) {
|
|
||||||
let uart = super::UART0_BASE as *mut char;
|
|
||||||
unsafe { uart.write_volatile(c) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn put_str(s: &str) {
|
|
||||||
let uart = super::UART0_BASE as *mut char;
|
|
||||||
for c in s.chars() {
|
|
||||||
unsafe { uart.write_volatile(c) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
use crate::plat::io::{RawConsole, Reader};
|
|
||||||
|
|
||||||
impl Reader for RawConsole {
|
|
||||||
#[inline]
|
|
||||||
fn get_char() -> char {
|
|
||||||
let uart = super::UART0_BASE as *mut char;
|
|
||||||
let line_sts = super::UART0_LSR as *mut u8;
|
|
||||||
while unsafe { line_sts.read_volatile() } & 0x01 == 0 {}
|
|
||||||
unsafe { uart.read_volatile() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
|
use super::board::console::init_early_console;
|
||||||
use super::layout::{__boot_stack_end, __bss_end, __tbss_end, __tbss_start};
|
use super::layout::{__boot_stack_end, __bss_end, __tbss_end, __tbss_start};
|
||||||
use super::tls::set_hart_id;
|
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -27,10 +27,10 @@ unsafe extern "C" fn _start(hart_id: usize, device_tree_addr: usize) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn pre_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
extern "C" fn pre_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
||||||
// TODO: multiboot
|
|
||||||
|
|
||||||
zero_bss();
|
zero_bss();
|
||||||
|
|
||||||
|
init_early_console();
|
||||||
|
|
||||||
// TODO: initialize page table
|
// TODO: initialize page table
|
||||||
|
|
||||||
crate::entry::rust_main(hart_id, device_tree_addr);
|
crate::entry::rust_main(hart_id, device_tree_addr);
|
||||||
|
@ -14,8 +14,8 @@ extern "C" {
|
|||||||
static __data_end: ExternSymbol;
|
static __data_end: ExternSymbol;
|
||||||
|
|
||||||
static __bss_start: ExternSymbol;
|
static __bss_start: ExternSymbol;
|
||||||
pub(crate) static __boot_stack_end: ExternSymbol;
|
pub static __boot_stack_end: ExternSymbol;
|
||||||
pub(crate) static __bss_end: ExternSymbol;
|
pub static __bss_end: ExternSymbol;
|
||||||
|
|
||||||
static __tss_start: ExternSymbol;
|
static __tss_start: ExternSymbol;
|
||||||
static __tss_end: ExternSymbol;
|
static __tss_end: ExternSymbol;
|
||||||
@ -23,6 +23,6 @@ extern "C" {
|
|||||||
static __tdata_start: ExternSymbol;
|
static __tdata_start: ExternSymbol;
|
||||||
static __tdata_end: ExternSymbol;
|
static __tdata_end: ExternSymbol;
|
||||||
|
|
||||||
pub(crate) static __tbss_start: ExternSymbol;
|
pub static __tbss_start: ExternSymbol;
|
||||||
pub(crate) static __tbss_end: ExternSymbol;
|
pub static __tbss_end: ExternSymbol;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
pub use board::BOOT_HART_ID;
|
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "board_virt")] {
|
if #[cfg(feature = "board_virt")] {
|
||||||
#[path = "board/virt/mod.rs"]
|
#[path = "board/virt/mod.rs"]
|
||||||
@ -12,6 +10,9 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Console: plat/console.rs
|
||||||
|
pub use board::console::EarlyConsole;
|
||||||
|
|
||||||
mod entry;
|
mod entry;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
mod lowlevel;
|
mod lowlevel;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::plat::console::CONSOLE;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use riscv::register::scause::{Interrupt as I, Trap as T};
|
use riscv::register::scause::{Interrupt as I, Trap as T};
|
||||||
@ -23,7 +24,13 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn trap_handler(_tf: &mut TrapContext) {
|
extern "C" fn kernel_trap_handler(tf: &mut TrapContext) {
|
||||||
|
// TODO: consider redesigning this, should we allow trap in kernel?
|
||||||
|
unsafe { CONSOLE.force_unlock() }
|
||||||
|
trap_handler(tf, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trap_handler(_tf: &mut TrapContext, _from_kernel: bool) {
|
||||||
let scause = riscv::register::scause::read();
|
let scause = riscv::register::scause::read();
|
||||||
trace!(
|
trace!(
|
||||||
"[Interrupt] cpu@{} scause: {:?}",
|
"[Interrupt] cpu@{} scause: {:?}",
|
||||||
|
11
kernel/src/drivers/mod.rs
Normal file
11
kernel/src/drivers/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// This will only implement some basic drivers (PLIC, UART, ...) to boot the kernel.
|
||||||
|
// For the rest of the drivers, we will implement them in root server.
|
||||||
|
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
use fdt::node::FdtNode;
|
||||||
|
|
||||||
|
pub trait Driver {
|
||||||
|
fn compatible() -> &'static [&'static str];
|
||||||
|
fn setup(_: FdtNode) -> Self;
|
||||||
|
}
|
6
kernel/src/drivers/serial/mod.rs
Normal file
6
kernel/src/drivers/serial/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use crate::drivers::Driver;
|
||||||
|
use crate::plat::console::ConsoleDevice;
|
||||||
|
|
||||||
|
pub trait SerialDriver: Driver + ConsoleDevice {}
|
||||||
|
|
||||||
|
pub mod uart16550;
|
36
kernel/src/drivers/serial/uart16550.rs
Normal file
36
kernel/src/drivers/serial/uart16550.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::drivers::serial::SerialDriver;
|
||||||
|
use crate::drivers::Driver;
|
||||||
|
use crate::plat::console::ConsoleDevice;
|
||||||
|
use fdt::node::FdtNode;
|
||||||
|
use uart_16550::MmioSerialPort;
|
||||||
|
|
||||||
|
pub struct Uart16550
|
||||||
|
where Uart16550: SerialDriver
|
||||||
|
{
|
||||||
|
port: MmioSerialPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for Uart16550 {
|
||||||
|
fn compatible() -> &'static [&'static str] {
|
||||||
|
&["ns16550", "ns16550a"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(fdt: FdtNode) -> Self {
|
||||||
|
let addr = fdt.reg().unwrap().next().unwrap().starting_address;
|
||||||
|
let mut serial_port = unsafe { MmioSerialPort::new(addr as usize) };
|
||||||
|
serial_port.init();
|
||||||
|
Uart16550 { port: serial_port }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleDevice for Uart16550 {
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
self.port.receive()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, byte: u8) {
|
||||||
|
self.port.send(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialDriver for Uart16550 {}
|
@ -1,9 +1,8 @@
|
|||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use fdt::Fdt;
|
use fdt::Fdt;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info, warn};
|
||||||
|
|
||||||
use crate::arch::BOOT_HART_ID;
|
use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver, CONSOLE};
|
||||||
use crate::plat::io::{RawConsole, Reader};
|
|
||||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
use crate::plat::lowlevel::{Hardware, LowLevel};
|
||||||
use crate::plat::timer::{Timer, TimerOps};
|
use crate::plat::timer::{Timer, TimerOps};
|
||||||
use crate::plat::trap::{Trap, TrapOps};
|
use crate::plat::trap::{Trap, TrapOps};
|
||||||
@ -14,21 +13,17 @@ pub static HART_ID: Cell<usize> = Cell::new(0);
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
pub extern "C" fn rust_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
||||||
HART_ID.set(hart_id);
|
HART_ID.set(hart_id);
|
||||||
|
|
||||||
crate::logging::init();
|
crate::logging::init();
|
||||||
|
|
||||||
|
info!("Kernel Started");
|
||||||
|
|
||||||
|
let fdt = unsafe { Fdt::from_ptr(device_tree_addr as *const u8).unwrap() };
|
||||||
|
setup_console(&fdt);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
{
|
||||||
|
info!("Running tests...");
|
||||||
crate::test_main();
|
crate::test_main();
|
||||||
// test_main will exit
|
|
||||||
|
|
||||||
info!("[rust_main] Kernel Started");
|
|
||||||
|
|
||||||
info!("hart_id = {}", hart_id);
|
|
||||||
debug!("device_tree_addr = {:#x}", device_tree_addr);
|
|
||||||
|
|
||||||
if hart_id != BOOT_HART_ID {
|
|
||||||
error!("No SMP support now, halting...");
|
|
||||||
Hardware::halt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: setup and start scheduler
|
// TODO: setup and start scheduler
|
||||||
@ -40,12 +35,13 @@ pub extern "C" fn rust_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
|||||||
Hardware::enable_interrupt();
|
Hardware::enable_interrupt();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let ch = RawConsole::get_char();
|
if let Some(ch) = CONSOLE.lock().try_read() {
|
||||||
debug!("Key: {}", ch);
|
debug!("Key: {}", ch);
|
||||||
if ch == 'q' {
|
if ch == b'q' {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- end ---
|
// --- end ---
|
||||||
|
|
||||||
@ -53,15 +49,14 @@ pub extern "C" fn rust_main(hart_id: usize, device_tree_addr: usize) -> ! {
|
|||||||
Hardware::shutdown(true);
|
Hardware::shutdown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_hello() {
|
fn setup_console(fdt: &Fdt) {
|
||||||
const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000;
|
// NOTE: ignore stdin: both stdin and stdout will go through stdout device
|
||||||
const HELLO: &[u8] = b"Hello World!\n";
|
match fdt
|
||||||
|
.chosen()
|
||||||
use uart_16550::MmioSerialPort;
|
.stdout()
|
||||||
let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_PORT_BASE_ADDRESS) };
|
.and_then(|stdout| ConsoleDriver::new(stdout))
|
||||||
serial_port.init();
|
{
|
||||||
|
None => warn!("No stdout device found or no compatible drivers found, falling back to platform default"),
|
||||||
for &byte in HELLO {
|
Some(driver) => set_console(driver),
|
||||||
serial_port.send(byte);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
|
use crate::entry::HART_ID;
|
||||||
|
use crate::plat::console::CONSOLE;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
use log::{LevelFilter, Log, Metadata, Record};
|
use log::{LevelFilter, Log, Metadata, Record};
|
||||||
|
|
||||||
use crate::plat::io::RawConsole;
|
|
||||||
|
|
||||||
struct SimpleLogger;
|
struct SimpleLogger;
|
||||||
|
|
||||||
impl Log for SimpleLogger {
|
impl Log for SimpleLogger {
|
||||||
@ -29,14 +28,12 @@ impl Log for SimpleLogger {
|
|||||||
("", "")
|
("", "")
|
||||||
};
|
};
|
||||||
|
|
||||||
RawConsole
|
CONSOLE
|
||||||
|
.lock()
|
||||||
.write_fmt(format_args!(
|
.write_fmt(format_args!(
|
||||||
"{color_prefix}[{}] [{}] {}{color_reset}\n",
|
"{color_prefix}[{}][HART{}] {}{color_reset}\n",
|
||||||
record.level(),
|
record.level(),
|
||||||
record
|
HART_ID.get(),
|
||||||
.module_path_static()
|
|
||||||
.or_else(|| record.module_path())
|
|
||||||
.unwrap_or("<n/a>"),
|
|
||||||
record.args(),
|
record.args(),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
// Features
|
// Features
|
||||||
#![feature(asm_const)]
|
#![feature(asm_const)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![feature(let_chains)]
|
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
@ -17,26 +16,14 @@
|
|||||||
|
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
// arch
|
mod arch;
|
||||||
pub mod arch;
|
mod drivers;
|
||||||
|
mod entry;
|
||||||
// rust language runtime
|
mod lang;
|
||||||
pub mod lang;
|
mod logging;
|
||||||
|
mod objects;
|
||||||
// entrypoint
|
mod plat;
|
||||||
pub mod entry;
|
mod utils;
|
||||||
|
|
||||||
// plat
|
|
||||||
pub mod plat;
|
|
||||||
|
|
||||||
// object
|
|
||||||
pub mod objects;
|
|
||||||
|
|
||||||
// logging
|
|
||||||
pub mod logging;
|
|
||||||
|
|
||||||
// utils
|
|
||||||
pub mod utils;
|
|
||||||
|
|
||||||
// test infrastructure
|
// test infrastructure
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
120
kernel/src/plat/console.rs
Normal file
120
kernel/src/plat/console.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
use crate::arch::EarlyConsole;
|
||||||
|
use crate::drivers::serial::uart16550::Uart16550;
|
||||||
|
use crate::drivers::Driver;
|
||||||
|
use fdt::node::FdtNode;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
macro_rules! create_console_driver {
|
||||||
|
(($($dynamic_driver:ident),+), ($($static_driver:ident),+)) => {
|
||||||
|
// A VERY DIRTY hack to work around dynamic dispatch
|
||||||
|
pub enum ConsoleDriver {
|
||||||
|
$($dynamic_driver($dynamic_driver),)+
|
||||||
|
$($static_driver($static_driver),)+
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleDriver {
|
||||||
|
pub fn new(fdt: FdtNode) -> Option<Self> {
|
||||||
|
if let Some(compatible) = fdt.compatible() {
|
||||||
|
$(
|
||||||
|
if compatible
|
||||||
|
.all()
|
||||||
|
.any(|s| $dynamic_driver::compatible().contains(&s))
|
||||||
|
{
|
||||||
|
return Some(ConsoleDriver::$dynamic_driver($dynamic_driver::setup(fdt)))
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConsoleDevice for ConsoleDriver {
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
match self {
|
||||||
|
$(ConsoleDriver::$dynamic_driver(driver) => driver.read(),)+
|
||||||
|
$(ConsoleDriver::$static_driver(driver) => driver.read(),)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_read(&mut self) -> Option<u8> {
|
||||||
|
match self {
|
||||||
|
$(ConsoleDriver::$dynamic_driver(driver) => driver.try_read(),)+
|
||||||
|
$(ConsoleDriver::$static_driver(driver) => driver.try_read(),)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, n: u8) {
|
||||||
|
match self {
|
||||||
|
$(ConsoleDriver::$dynamic_driver(driver) => driver.write(n),)+
|
||||||
|
$(ConsoleDriver::$static_driver(driver) => driver.write(n),)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_str(&mut self, s: &str) {
|
||||||
|
match self {
|
||||||
|
$(ConsoleDriver::$dynamic_driver(driver) => driver.write_str(s),)+
|
||||||
|
$(ConsoleDriver::$static_driver(driver) => driver.write_str(s),)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
create_console_driver!((Uart16550), (SilenceConsole, EarlyConsole));
|
||||||
|
|
||||||
|
impl core::fmt::Write for ConsoleDriver {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
ConsoleDevice::write_str(self, s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SilenceConsole;
|
||||||
|
|
||||||
|
impl ConsoleDevice for SilenceConsole {
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, _: u8) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ConsoleDevice {
|
||||||
|
/// Blocking read
|
||||||
|
fn read(&mut self) -> u8;
|
||||||
|
/// Non-blocking read
|
||||||
|
fn try_read(&mut self) -> Option<u8> {
|
||||||
|
Some(self.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a byte
|
||||||
|
fn write(&mut self, _: u8);
|
||||||
|
/// Write a str
|
||||||
|
fn write_str(&mut self, s: &str) {
|
||||||
|
for byte in s.bytes() {
|
||||||
|
self.write(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static CONSOLE: Mutex<ConsoleDriver> =
|
||||||
|
Mutex::new(ConsoleDriver::SilenceConsole(SilenceConsole));
|
||||||
|
|
||||||
|
pub fn set_console(driver: ConsoleDriver) {
|
||||||
|
*CONSOLE.lock() = driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn print_with_console() {
|
||||||
|
CONSOLE.lock().write(b'A');
|
||||||
|
CONSOLE
|
||||||
|
.lock()
|
||||||
|
.write_fmt(format_args!("B {}\n", 0x42))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
pub struct RawConsole
|
|
||||||
where RawConsole: Printer + Reader;
|
|
||||||
|
|
||||||
pub trait Printer: core::fmt::Write {
|
|
||||||
fn put_char(c: char);
|
|
||||||
|
|
||||||
fn put_str(s: &str) {
|
|
||||||
s.chars().for_each(Self::put_char);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_line(s: &str) {
|
|
||||||
Self::put_str(s);
|
|
||||||
Self::put_char('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_num(mut num: usize) {
|
|
||||||
if num == 0 {
|
|
||||||
Self::put_char('0');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let digits = "0123456789".as_bytes();
|
|
||||||
let mut buf = [0u8; 10];
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
while num != 0 {
|
|
||||||
buf[i] = digits[num % 10];
|
|
||||||
num /= 10;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[..i]
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.for_each(|c| Self::put_char(*c as char));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_hex(mut num: usize) {
|
|
||||||
if num == 0 {
|
|
||||||
Self::put_str("0x0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let alphabet = "0123456789abcdef".as_bytes();
|
|
||||||
let mut buf = [0u8; 8];
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
while num != 0 {
|
|
||||||
buf[i] = alphabet[num % 16];
|
|
||||||
num /= 16;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::put_str("0x");
|
|
||||||
buf[..i]
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.for_each(|c| Self::put_char(*c as char));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Write for RawConsole {
|
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
|
||||||
Self::put_str(s);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Reader {
|
|
||||||
fn get_char() -> char;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test_case]
|
|
||||||
fn print_with_console() {
|
|
||||||
RawConsole::put_char('A');
|
|
||||||
RawConsole::put_str("BC");
|
|
||||||
RawConsole::put_line("DEF");
|
|
||||||
RawConsole::put_num(123);
|
|
||||||
RawConsole::put_hex(0xdeadbeef);
|
|
||||||
RawConsole::put_line("");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
pub mod io;
|
pub mod console;
|
||||||
pub mod lowlevel;
|
pub mod lowlevel;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod trap;
|
pub mod trap;
|
||||||
|
Loading…
Reference in New Issue
Block a user