Skip to content

Commit 6874ab3

Browse files
feat(kdbg): for serial debugging
Signed-off-by: Anhad Singh <[email protected]>
1 parent beca7e7 commit 6874ab3

File tree

2 files changed

+118
-15
lines changed

2 files changed

+118
-15
lines changed

src/aero_kernel/src/drivers/uart_16550.rs

+59-13
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ use core::fmt::Write;
2020

2121
use spin::Once;
2222

23+
use crate::arch::interrupts::{self, InterruptStack};
2324
use crate::arch::io;
25+
use crate::userland::task::Task;
2426
use crate::utils::sync::Mutex;
2527

26-
static COM_1: Once<Mutex<SerialPort>> = Once::new();
28+
use alloc::sync::Arc;
29+
use alloc::vec::Vec;
30+
31+
pub static COM_1: Once<Mutex<SerialPort>> = Once::new();
2732

2833
bitflags::bitflags! {
2934
pub struct InterruptEnable: u8 {
@@ -95,25 +100,35 @@ impl SerialPort {
95100
}
96101

97102
pub fn send_byte(&mut self, byte: u8) {
98-
unsafe {
99-
match byte {
100-
8 | 0x7F => {
101-
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
103+
match byte {
104+
8 | 0x7F => {
105+
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
106+
unsafe {
102107
io::outb(self.0, 8);
108+
}
103109

104-
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
110+
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
111+
unsafe {
105112
io::outb(self.0, b' ');
113+
}
106114

107-
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
115+
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
116+
unsafe {
108117
io::outb(self.0, 8);
109118
}
110-
_ => {
111-
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
112-
io::outb(self.0, byte)
119+
}
120+
_ => {
121+
self.wait_for_line_status(LineStatus::OUTPUT_EMPTY);
122+
unsafe {
123+
io::outb(self.0, byte);
113124
}
114125
}
115126
}
116127
}
128+
129+
pub fn read_byte(&mut self) -> u8 {
130+
unsafe { io::inb(self.0) }
131+
}
117132
}
118133

119134
impl fmt::Write for SerialPort {
@@ -126,15 +141,44 @@ impl fmt::Write for SerialPort {
126141
}
127142
}
128143

144+
fn irq_handler(_stack: &mut InterruptStack) {
145+
if !unsafe { COM_1.get_unchecked() }
146+
.lock_irq()
147+
.line_status()
148+
.contains(LineStatus::INPUT_FULL)
149+
{
150+
return;
151+
}
152+
153+
(*LISTENERS)
154+
.lock_irq()
155+
.iter()
156+
.for_each(|task| task.wake_up());
157+
}
158+
159+
lazy_static::lazy_static! {
160+
static ref LISTENERS: Mutex<Vec<Arc<Task>>> = Mutex::new(Vec::new());
161+
}
162+
163+
pub fn register_listener(task: Arc<Task>) {
164+
(*LISTENERS).lock_irq().push(task);
165+
}
166+
129167
/// Initialize the serial ports if available.
130168
pub fn init() {
131169
unsafe {
132-
let com_1 = SerialPort::new(0x3F8).init();
133-
170+
let com_1 = SerialPort::new(0x3f8).init();
134171
COM_1.call_once(move || Mutex::new(com_1));
135172
}
136173
}
137174

175+
pub fn setup_interrupts() {
176+
let vector = interrupts::allocate_vector();
177+
interrupts::register_handler(vector, irq_handler);
178+
179+
crate::arch::apic::io_apic_setup_legacy_irq(4, vector, 1);
180+
}
181+
138182
pub macro serial_print($($arg:tt)*) {
139183
crate::drivers::uart_16550::_serial_print(format_args!($($arg)*))
140184
}
@@ -147,6 +191,8 @@ pub macro serial_println {
147191
#[doc(hidden)]
148192
pub fn _serial_print(args: fmt::Arguments) {
149193
if let Some(c) = COM_1.get() {
150-
c.lock().write_fmt(args).expect("failed to write to COM1")
194+
c.lock_irq()
195+
.write_fmt(args)
196+
.expect("failed to write to COM1")
151197
}
152198
}

src/aero_kernel/src/main.rs

+59-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@
4949
associated_type_defaults,
5050
trait_upcasting,
5151
asm_const,
52-
sync_unsafe_cell,
53-
// effects
52+
sync_unsafe_cell
5453
)]
5554
// TODO(andypython): can we remove the dependency of "prelude_import" and "lang_items"?
5655
// `lang_items` => is currently used for the personality function (`rust_eh_personality`).
@@ -171,7 +170,9 @@ fn aero_main() -> ! {
171170
// Now that all of the essential initialization is done we are going to schedule
172171
// the kernel main thread.
173172
let init = Task::new_kernel(kernel_main_thread, true);
173+
let kdbg = Task::new_kernel(kernel_dbg_thread, true);
174174
scheduler::get_scheduler().register_task(init);
175+
scheduler::get_scheduler().register_task(kdbg);
175176

176177
unsafe {
177178
interrupts::enable_interrupts();
@@ -212,6 +213,62 @@ fn kernel_main_thread() {
212213
unreachable!()
213214
}
214215

216+
fn kernel_dbg_thread() {
217+
use core::fmt::Write;
218+
219+
use crate::drivers::uart::{self, LineStatus, COM_1};
220+
use crate::userland::task::TaskId;
221+
use crate::utils::sync::WaitQueue;
222+
223+
uart::setup_interrupts();
224+
225+
let input_wq = WaitQueue::new();
226+
let this_task = scheduler::current_thread();
227+
uart::register_listener(this_task.clone());
228+
229+
let com_1 = COM_1.get().unwrap();
230+
231+
loop {
232+
let mut input = String::new();
233+
234+
loop {
235+
let mut com_1 = input_wq
236+
.block_on(com_1, |com_1| {
237+
com_1.line_status().contains(LineStatus::INPUT_FULL)
238+
})
239+
.unwrap();
240+
241+
let c = com_1.read_byte() as char;
242+
243+
if c == '\r' {
244+
writeln!(com_1).unwrap();
245+
break;
246+
}
247+
248+
input.push(c);
249+
write!(com_1, "{c}").unwrap();
250+
}
251+
252+
let mut commands = input.split_whitespace();
253+
254+
if let Some(name) = commands.next() {
255+
match name {
256+
"ps" => scheduler::get_scheduler().log_ptable(),
257+
"wake" => {
258+
log::warn!("kdbg: forcefully waking up task");
259+
let id = commands.next().unwrap().parse::<usize>().unwrap();
260+
scheduler::get_scheduler()
261+
.find_task(TaskId::new(id))
262+
.unwrap()
263+
.wake_up();
264+
}
265+
266+
_ => log::warn!("kdbg: unknown command {name:?}"),
267+
}
268+
}
269+
}
270+
}
271+
215272
extern "C" fn aero_ap_main(ap_id: usize) -> ! {
216273
log::info!("AP{}: Loaded userland", ap_id);
217274

0 commit comments

Comments
 (0)