1
0

Initialize PIC

This commit is contained in:
Mark 2025-02-27 21:35:00 -08:00
parent 7f0d1f9d59
commit a81ef17429
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
5 changed files with 121 additions and 14 deletions

View File

@ -1,4 +1,5 @@
#[macro_use]
pub mod serial;
pub mod pic;
pub mod vga;

88
tetros/src/drivers/pic.rs Normal file
View File

@ -0,0 +1,88 @@
use core::arch::asm;
/// IO base address for master PIC
const PIC_A: u32 = 0x20;
const PIC_A_COMMAND: u32 = PIC_A;
const PIC_A_DATA: u32 = PIC_A + 1;
/// IO base address for slave PIC
const PIC_B: u32 = 0xA0;
const PIC_B_COMMAND: u32 = PIC_B;
const PIC_B_DATA: u32 = PIC_B + 1;
/// PIC `EOI` command
const CMD_EOI: u8 = 0x20;
unsafe fn outb(port: u32, value: u8) {
asm!(
"out dx, al",
in("dx") port,
in("al") value,
);
}
/// A driver for the PIC
///
/// Reference:
/// - https://wiki.osdev.org/8259_PIC
/// - https://os.phil-opp.com/hardware-interrupts
pub struct PICDriver {
offset_pic_a: u8,
offset_pic_b: u8,
}
impl PICDriver {
pub const fn new(offset_pic_a: u8, offset_pic_b: u8) -> Self {
Self {
offset_pic_a,
offset_pic_b,
}
}
fn send_a_cmd(&self, cmd: u8) {
unsafe { outb(PIC_A_COMMAND, cmd) }
}
fn send_a_data(&self, cmd: u8) {
unsafe { outb(PIC_A_DATA, cmd) }
}
fn send_b_cmd(&self, cmd: u8) {
unsafe { outb(PIC_B_COMMAND, cmd) }
}
fn send_b_data(&self, cmd: u8) {
unsafe { outb(PIC_B_DATA, cmd) }
}
pub fn send_eoi(&self, irq: u8) {
if irq > 8 {
self.send_b_cmd(CMD_EOI);
}
self.send_a_cmd(CMD_EOI);
}
pub fn init(&mut self) {
const ICW1_ICW4: u8 = 0x01; /* Indicates that ICW4 will be present */
const ICW1_INIT: u8 = 0x10; /* Initialization - required! */
const ICW4_8086: u8 = 0x01; /* 8086/88 (MCS-80/85) mode */
self.send_a_cmd(ICW1_INIT | ICW1_ICW4);
self.send_b_cmd(ICW1_INIT | ICW1_ICW4);
self.send_a_data(self.offset_pic_a); // ICW2: Master PIC vector offset
self.send_b_data(self.offset_pic_b); // ICW2: Slave PIC vector offset
self.send_a_data(4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
self.send_b_data(2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
// ICW4: have the PICs use 8086 mode (and not 8080 mode)
self.send_a_data(ICW4_8086);
self.send_b_data(ICW4_8086);
// Unmask both PICs
self.send_a_data(0);
self.send_b_data(0);
}
}

View File

@ -29,13 +29,9 @@ pub fn _print(args: core::fmt::Arguments<'_>) {
.write_fmt(args)
.expect("Printing to serial failed");
// TODO:
// This is broken, triple-faults right away.
// Uncomment after enabling interrupts in the bootloader & fixing idt
//
// unsafe {
// asm!("sti", options(preserves_flags, nostack));
// }
unsafe {
asm!("sti", options(preserves_flags, nostack));
}
}
/// Prints to the host through the serial interface.

View File

@ -389,8 +389,11 @@ pub struct InterruptDescriptorTable {
/// vector nr. 31
reserved_3: Entry<HandlerFunc>,
/// User-defined interrupts can be initiated either by system logic or software. They occur
/// when:
/// User-defined interrupts can be initiated either by system logic or software.
/// `interrupts[0]` is interrupt vector 32.
///
///
/// These occur when:
///
/// - System logic signals an external interrupt request to the processor. The signaling
/// mechanism and the method of communicating the interrupt vector to the processor are

View File

@ -8,7 +8,7 @@ use core::arch::asm;
use lazy_static::lazy_static;
use spin::Mutex;
use drivers::vga::Vga13h;
use drivers::{pic::PICDriver, vga::Vga13h};
use idt::{InterruptDescriptorTable, InterruptStackFrame};
use os::thunk::ThunkData;
use tetrisboard::TetrisBoard;
@ -21,18 +21,35 @@ mod tetrisboard;
mod drivers;
pub(crate) static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
pub(crate) static PIC: Mutex<PICDriver> = Mutex::new(PICDriver::new(32, 32 + 8));
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.divide_error.set_handler_fn(breakpoint_handler);
idt.divide_error.set_handler_fn(divide_handler);
idt.double_fault.set_handler_fn(double_fault_handler);
idt.interrupts[0].set_handler_fn(timer_handler);
idt
};
}
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
println!("EXCEPTION {:?}", stack_frame);
extern "x86-interrupt" fn divide_handler(stack_frame: InterruptStackFrame) {
println!("DIVIDE ERROR {:?}", stack_frame);
}
extern "x86-interrupt" fn timer_handler(stack_frame: InterruptStackFrame) {
println!("TIMER {:?}", stack_frame);
PIC.lock().send_eoi(32);
}
extern "x86-interrupt" fn double_fault_handler(
stack_frame: InterruptStackFrame,
error_code: u32,
) -> ! {
panic!("DOUBLE FAULT (err = 0x{error_code:x}\n{:#?}", stack_frame);
}
#[no_mangle]
@ -61,8 +78,10 @@ pub unsafe extern "C" fn start(
}
{
// Initialize OS
// Initialize IDT
IDT.load();
let mut pic = PIC.lock();
pic.init();
}
// Clear screen