Skip to content

Commit

Permalink
Add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
mrgian committed Mar 30, 2023
1 parent 1780bfa commit e59296a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 45 deletions.
42 changes: 28 additions & 14 deletions kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const STACK_START: u32 = KERNEL_START + KERNEL_SIZE + STACK_SIZE;

const VERSION: &str = env!("CARGO_PKG_VERSION");

const TIMER_INT: u8 = 32;
const KEYBOARD_INT: u8 = 33;

#[no_mangle]
#[link_section = ".start"]
pub extern "C" fn _start() -> ! {
Expand All @@ -33,26 +36,33 @@ pub extern "C" fn _start() -> ! {

println!("Welcome to Felix {}!", VERSION);

//let pics = Pics::new();
//init programmable interrupt controllers
PICS.init();

//init interrupt descriptor table
let mut idt = InterruptDescriptorTable::new();

//add CPU exceptions to idt
idt.add_exceptions();
idt.add(32, timer as u32);
idt.add(33, keyboard as u32);

//add hardware interrupts to idt
idt.add(TIMER_INT as usize, timer as u32);
idt.add(KEYBOARD_INT as usize, keyboard as u32);

//load idt
idt.load();

//enable hardware interrupts
unsafe {
asm!("sti");
}

println!("Not crashed!");

unsafe {
asm!("hlt");
//halt cpu while waiting for interrupts
loop {
unsafe {
asm!("hlt");
}
}

loop {}
}

#[panic_handler]
Expand All @@ -62,20 +72,23 @@ fn panic(info: &PanicInfo) -> ! {
loop {}
}

//timer handler
#[naked]
pub extern "C" fn timer() {
unsafe {
asm!("call print_dot", "iretd", options(noreturn));
asm!("call timer_handler", "iretd", options(noreturn));
}
}

#[no_mangle]
pub extern "C" fn print_dot() {
pub extern "C" fn timer_handler() {
//print!(".");

PICS.end_interrupt(32);
PICS.end_interrupt(TIMER_INT);
}


//keyboard handler
#[naked]
pub extern "C" fn keyboard() {
unsafe {
Expand All @@ -85,12 +98,13 @@ pub extern "C" fn keyboard() {

#[no_mangle]
pub extern "C" fn keyboard_handler() {
//read scancode from keyboard controller
let scancode: u8;
unsafe {
asm!("in al, dx", out("al") scancode, in("dx") 0x60 as u16);
}

print!("{} ", scancode);
println!("KEYBOARD INTERRUPT! Scancode: {:X} ", scancode);

PICS.end_interrupt(33);
PICS.end_interrupt(KEYBOARD_INT);
}
91 changes: 60 additions & 31 deletions kernel/src/pic.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
use core::arch::asm;

const PRIMARY_PIC_COMMAND_PORT: u8 = 0x20;
const PRIMARY_PIC_DATA_PORT: u8 = 0x21;
//master pic ports
const MASTER_PIC_COMMAND_PORT: u8 = 0x20;
const MASTER_PIC_DATA_PORT: u8 = 0x21;

const SECONDARY_PIC_COMMAND_PORT: u8 = 0xa0;
const SECONDARY_PIC_DATA_PORT: u8 = 0xa1;
//slave pic ports
const SLAVE_PIC_COMMAND_PORT: u8 = 0xa0;
const SLAVE_PIC_DATA_PORT: u8 = 0xa1;

//command bytes
const COMMAND_INIT: u8 = 0x11;
const COMMAND_EOF: u8 = 0x20;

//pic 8086 mode
const MODE: u8 = 0x01;

const INT_OFFSET: u8 = 32;
//where to start remapping IRQs, start from 32 because 0-31 interrupts are used by CPU exceptions
const OFFSET: u8 = 32;

//how many interrupts a pic can handle
const IRQ_COUNT: u8 = 8;


//define a global PICS so it can be accessed from everywhere
pub static PICS: Pics = Pics {
primary: Pic {
offset: INT_OFFSET,
command_port: PRIMARY_PIC_COMMAND_PORT,
data_port: PRIMARY_PIC_DATA_PORT,
master: Pic {
offset: OFFSET,
command_port: MASTER_PIC_COMMAND_PORT,
data_port: MASTER_PIC_DATA_PORT,
},
secondary: Pic {
offset: INT_OFFSET + 8, //each pic can handle 8 interrupts, so secondary pic handles the ints after the primary ones
command_port: SECONDARY_PIC_COMMAND_PORT,
data_port: SECONDARY_PIC_DATA_PORT,
slave: Pic {
offset: OFFSET + IRQ_COUNT, //each pic can handle 8 interrupts, so slave pic handles the ints after the master ones
command_port: SLAVE_PIC_COMMAND_PORT,
data_port: SLAVE_PIC_DATA_PORT,
},
};

//single programmable interrupt controller
struct Pic {
offset: u8,
command_port: u8,
data_port: u8,
}

impl Pic {
//read byte from pic data port
pub fn read_data(&self) -> u8 {
let data: u8;
unsafe {
Expand All @@ -42,77 +54,94 @@ impl Pic {
data
}

//write byte to pic data port
pub fn write_data(&self, data: u8) {
unsafe {
asm!("out dx, al", in("dx") self.data_port as u16, in("al") data);
}
}

//send command to pic
pub fn send_command(&self, command: u8) {
unsafe {
asm!("out dx, al", in("dx") self.command_port as u16, in("al") command);
}
}

//notify pic that interrupts has ended
pub fn end_interrupt(&self) {
unsafe {
asm!("out dx, al", in("dx") self.command_port as u16, in("al") COMMAND_EOF);
}
}

//check if pic is handling interrupt
pub fn handles_interrupt(&self, interupt: u8) -> bool {
self.offset <= interupt && interupt < self.offset + 8
}
}

//two pics chained one after another
pub struct Pics {
primary: Pic,
secondary: Pic,
master: Pic,
slave: Pic,
}

impl Pics {
//initialize both pics
pub fn init(&self) {
let mask1 = self.primary.read_data();
let mask2 = self.secondary.read_data();
//backup masks, need to restore later
let mask1 = self.master.read_data();
let mask2 = self.slave.read_data();

self.primary.send_command(COMMAND_INIT);
//send init command
self.master.send_command(COMMAND_INIT);
wait();
self.secondary.send_command(COMMAND_INIT);
self.slave.send_command(COMMAND_INIT);
wait();

self.primary.write_data(self.primary.offset);
//set offset
self.master.write_data(self.master.offset);
wait();
self.secondary.write_data(self.secondary.offset);
self.slave.write_data(self.slave.offset);
wait();

self.primary.write_data(4);
//tell master pic that there is a connected slave pic on IRQ2
self.master.write_data(4);
wait();
self.secondary.write_data(2);
//tell slave pic that he is slave
self.slave.write_data(2);
wait();

self.primary.write_data(MODE);
//set 8086 mode
self.master.write_data(MODE);
wait();
self.secondary.write_data(MODE);
self.slave.write_data(MODE);
wait();

self.primary.write_data(mask1);
self.secondary.write_data(mask2);
//restore mask
self.master.write_data(mask1);
self.slave.write_data(mask2);
}

//check if one of the pics is handling an interrupt
pub fn handles_interrupt(&self, interrupt: u8) -> bool {
self.primary.handles_interrupt(interrupt) || self.secondary.handles_interrupt(interrupt)
self.master.handles_interrupt(interrupt) || self.slave.handles_interrupt(interrupt)
}

//notify pics that current interrupt has ended
pub fn end_interrupt(&self, interrupt: u8) {
if self.handles_interrupt(interrupt) {
if self.secondary.handles_interrupt(interrupt) {
self.secondary.end_interrupt();
if self.slave.handles_interrupt(interrupt) {
self.slave.end_interrupt();
}
self.primary.end_interrupt();
self.master.end_interrupt();
}
}
}

//since pics may not be very fast, we need a wait function
//this simply writes data to an unused port, should take some time
pub fn wait() {
unsafe {
asm!("out dx, al", in("dx") 0x80 as u16, in("al") 0 as u8);
Expand Down

0 comments on commit e59296a

Please sign in to comment.