Initialize PIC
This commit is contained in:
parent
7f0d1f9d59
commit
a81ef17429
@ -1,4 +1,5 @@
|
||||
#[macro_use]
|
||||
pub mod serial;
|
||||
|
||||
pub mod pic;
|
||||
pub mod vga;
|
||||
|
88
tetros/src/drivers/pic.rs
Normal file
88
tetros/src/drivers/pic.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user