Skip to content

Commit

Permalink
feat(kdbg): for serial debugging
Browse files Browse the repository at this point in the history
Signed-off-by: Anhad Singh <[email protected]>
  • Loading branch information
Andy-Python-Programmer committed Jul 4, 2024
1 parent beca7e7 commit 6874ab3
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 15 deletions.
72 changes: 59 additions & 13 deletions src/aero_kernel/src/drivers/uart_16550.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ use core::fmt::Write;

use spin::Once;

use crate::arch::interrupts::{self, InterruptStack};
use crate::arch::io;
use crate::userland::task::Task;
use crate::utils::sync::Mutex;

static COM_1: Once<Mutex<SerialPort>> = Once::new();
use alloc::sync::Arc;
use alloc::vec::Vec;

pub static COM_1: Once<Mutex<SerialPort>> = Once::new();

bitflags::bitflags! {
pub struct InterruptEnable: u8 {
Expand Down Expand Up @@ -95,25 +100,35 @@ impl SerialPort {
}

pub fn send_byte(&mut self, byte: u8) {
unsafe {
match byte {
8 | 0x7F => {
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
match byte {
8 | 0x7F => {
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
unsafe {
io::outb(self.0, 8);
}

self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
unsafe {
io::outb(self.0, b' ');
}

self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
unsafe {
io::outb(self.0, 8);
}
_ => {
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
io::outb(self.0, byte)
}
_ => {
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
unsafe {
io::outb(self.0, byte);
}
}
}
}

pub fn read_byte(&mut self) -> u8 {
unsafe { io::inb(self.0) }
}
}

impl fmt::Write for SerialPort {
Expand All @@ -126,15 +141,44 @@ impl fmt::Write for SerialPort {
}
}

fn irq_handler(_stack: &mut InterruptStack) {
if !unsafe { COM_1.get_unchecked() }
.lock_irq()
.line_status()
.contains(LineStatus::INPUT_FULL)
{
return;
}

(*LISTENERS)
.lock_irq()
.iter()
.for_each(|task| task.wake_up());
}

lazy_static::lazy_static! {
static ref LISTENERS: Mutex<Vec<Arc<Task>>> = Mutex::new(Vec::new());
}

pub fn register_listener(task: Arc<Task>) {
(*LISTENERS).lock_irq().push(task);
}

/// Initialize the serial ports if available.
pub fn init() {
unsafe {
let com_1 = SerialPort::new(0x3F8).init();

let com_1 = SerialPort::new(0x3f8).init();
COM_1.call_once(move || Mutex::new(com_1));
}
}

pub fn setup_interrupts() {
let vector = interrupts::allocate_vector();
interrupts::register_handler(vector, irq_handler);

crate::arch::apic::io_apic_setup_legacy_irq(4, vector, 1);
}

pub macro serial_print($($arg:tt)*) {
crate::drivers::uart_16550::_serial_print(format_args!($($arg)*))
}
Expand All @@ -147,6 +191,8 @@ pub macro serial_println {
#[doc(hidden)]
pub fn _serial_print(args: fmt::Arguments) {
if let Some(c) = COM_1.get() {
c.lock().write_fmt(args).expect("failed to write to COM1")
c.lock_irq()
.write_fmt(args)
.expect("failed to write to COM1")
}
}
61 changes: 59 additions & 2 deletions src/aero_kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@
associated_type_defaults,
trait_upcasting,
asm_const,
sync_unsafe_cell,
// effects
sync_unsafe_cell
)]
// TODO(andypython): can we remove the dependency of "prelude_import" and "lang_items"?
// `lang_items` => is currently used for the personality function (`rust_eh_personality`).
Expand Down Expand Up @@ -171,7 +170,9 @@ fn aero_main() -> ! {
// Now that all of the essential initialization is done we are going to schedule
// the kernel main thread.
let init = Task::new_kernel(kernel_main_thread, true);
let kdbg = Task::new_kernel(kernel_dbg_thread, true);
scheduler::get_scheduler().register_task(init);
scheduler::get_scheduler().register_task(kdbg);

unsafe {
interrupts::enable_interrupts();
Expand Down Expand Up @@ -212,6 +213,62 @@ fn kernel_main_thread() {
unreachable!()
}

fn kernel_dbg_thread() {
use core::fmt::Write;

use crate::drivers::uart::{self, LineStatus, COM_1};
use crate::userland::task::TaskId;
use crate::utils::sync::WaitQueue;

uart::setup_interrupts();

let input_wq = WaitQueue::new();
let this_task = scheduler::current_thread();
uart::register_listener(this_task.clone());

let com_1 = COM_1.get().unwrap();

loop {
let mut input = String::new();

loop {
let mut com_1 = input_wq
.block_on(com_1, |com_1| {
com_1.line_status().contains(LineStatus::INPUT_FULL)
})
.unwrap();

let c = com_1.read_byte() as char;

if c == '\r' {
writeln!(com_1).unwrap();
break;
}

input.push(c);
write!(com_1, "{c}").unwrap();
}

let mut commands = input.split_whitespace();

if let Some(name) = commands.next() {
match name {
"ps" => scheduler::get_scheduler().log_ptable(),
"wake" => {
log::warn!("kdbg: forcefully waking up task");
let id = commands.next().unwrap().parse::<usize>().unwrap();
scheduler::get_scheduler()
.find_task(TaskId::new(id))
.unwrap()
.wake_up();
}

_ => log::warn!("kdbg: unknown command {name:?}"),
}
}
}
}

extern "C" fn aero_ap_main(ap_id: usize) -> ! {
log::info!("AP{}: Loaded userland", ap_id);

Expand Down

0 comments on commit 6874ab3

Please sign in to comment.