Fill in all exception and IRQ entries. Handle PIT, keyboard IRQs
This commit is contained in:
parent
a9a8c2b340
commit
f784e9a06a
|
@ -8,5 +8,5 @@ hole_list_allocator = { path = "../../alloc/hole_list_allocator"}
|
||||||
spin = "*"
|
spin = "*"
|
||||||
|
|
||||||
[dependencies.x86]
|
[dependencies.x86]
|
||||||
default-features = false
|
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
default-features = false
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use core::mem;
|
|
||||||
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||||
|
|
||||||
/// This must be used by the kernel to ensure that context switches are done atomically
|
/// This must be used by the kernel to ensure that context switches are done atomically
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
use externs::memset;
|
|
||||||
use memory::Frame;
|
use memory::Frame;
|
||||||
use paging::{ActivePageTable, PhysicalAddress, entry};
|
use paging::{ActivePageTable, PhysicalAddress, entry};
|
||||||
|
|
9
arch/x86_64/src/device/mod.rs
Normal file
9
arch/x86_64/src/device/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use paging::ActivePageTable;
|
||||||
|
|
||||||
|
pub mod display;
|
||||||
|
pub mod ps2;
|
||||||
|
|
||||||
|
pub unsafe fn init(active_table: &mut ActivePageTable){
|
||||||
|
display::init(active_table);
|
||||||
|
ps2::init();
|
||||||
|
}
|
73
arch/x86_64/src/device/ps2.rs
Normal file
73
arch/x86_64/src/device/ps2.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use io::{Io, Pio, ReadOnly, WriteOnly};
|
||||||
|
|
||||||
|
pub static PS2: Mutex<Ps2> = Mutex::new(Ps2::new());
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
PS2.lock().init();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod status {
|
||||||
|
bitflags! {
|
||||||
|
pub flags Flags: u8 {
|
||||||
|
const OUTPUT_FULL = 1,
|
||||||
|
const INPUT_FULL = 1 << 1,
|
||||||
|
const SYSTEM = 1 << 2,
|
||||||
|
const COMMAND = 1 << 3,
|
||||||
|
const TIME_OUT = 1 << 6,
|
||||||
|
const PARITY = 1 << 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod config {
|
||||||
|
bitflags! {
|
||||||
|
pub flags Flags: u8 {
|
||||||
|
const FIRST_INTERRUPT = 1,
|
||||||
|
const SECOND_INTERRUPT = 1 << 1,
|
||||||
|
const SYSTEM = 1 << 2,
|
||||||
|
const FIRST_DISABLE = 1 << 4,
|
||||||
|
const SECOND_DISABLE = 1 << 5,
|
||||||
|
const FIRST_TRANSLATE = 1 << 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Command {
|
||||||
|
ReadConfig = 0x20,
|
||||||
|
WriteConfig = 0x60,
|
||||||
|
DisableSecond = 0xA7,
|
||||||
|
EnableSecond = 0xA8,
|
||||||
|
TestSecond = 0xA9,
|
||||||
|
TestController = 0xAA,
|
||||||
|
TestFirst = 0xAB,
|
||||||
|
Diagnostic = 0xAC,
|
||||||
|
DisableFirst = 0xAD,
|
||||||
|
EnableFirst = 0xAE,
|
||||||
|
WriteSecond = 0xD4
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ps2 {
|
||||||
|
pub data: Pio<u8>,
|
||||||
|
pub status: ReadOnly<Pio<u8>>,
|
||||||
|
pub command: WriteOnly<Pio<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ps2 {
|
||||||
|
pub const fn new() -> Ps2 {
|
||||||
|
Ps2 {
|
||||||
|
data: Pio::new(0x60),
|
||||||
|
status: ReadOnly::new(Pio::new(0x64)),
|
||||||
|
command: WriteOnly::new(Pio::new(0x64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
print!("Status {:?}\n", status::Flags::from_bits_truncate(self.status.read()));
|
||||||
|
|
||||||
|
self.command.write(Command::ReadConfig as u8);
|
||||||
|
print!("Config {:?}\n", config::Flags::from_bits_truncate(self.data.read()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use x86::dtables::{self, DescriptorTablePointer};
|
use x86::dtables::{self, DescriptorTablePointer};
|
||||||
|
|
||||||
use interrupt::halt;
|
use interrupt::*;
|
||||||
|
|
||||||
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
|
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
|
||||||
limit: 0,
|
limit: 0,
|
||||||
|
@ -14,69 +14,56 @@ pub unsafe fn init() {
|
||||||
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
||||||
IDTR.base = IDT.as_ptr() as u64;
|
IDTR.base = IDT.as_ptr() as u64;
|
||||||
|
|
||||||
for entry in IDT[0..32].iter_mut() {
|
// Set up exceptions
|
||||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
IDT[0].set_func(exception::divide_by_zero);
|
||||||
entry.set_offset(8, exception as usize);
|
IDT[1].set_func(exception::debug);
|
||||||
}
|
IDT[2].set_func(exception::non_maskable);
|
||||||
IDT[13].set_offset(8, protection_fault as usize);
|
IDT[3].set_func(exception::breakpoint);
|
||||||
IDT[14].set_offset(8, page_fault as usize);
|
IDT[4].set_func(exception::overflow);
|
||||||
for entry in IDT[32..].iter_mut() {
|
IDT[5].set_func(exception::bound_range);
|
||||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
IDT[6].set_func(exception::invalid_opcode);
|
||||||
entry.set_offset(8, blank as usize);
|
IDT[7].set_func(exception::device_not_available);
|
||||||
}
|
IDT[8].set_func(exception::double_fault);
|
||||||
IDT[0x80].set_offset(8, syscall as usize);
|
// 9 no longer available
|
||||||
|
IDT[10].set_func(exception::invalid_tss);
|
||||||
|
IDT[11].set_func(exception::segment_not_present);
|
||||||
|
IDT[12].set_func(exception::stack_segment);
|
||||||
|
IDT[13].set_func(exception::protection);
|
||||||
|
IDT[14].set_func(exception::page);
|
||||||
|
// 15 reserved
|
||||||
|
IDT[16].set_func(exception::fpu);
|
||||||
|
IDT[17].set_func(exception::alignment_check);
|
||||||
|
IDT[18].set_func(exception::machine_check);
|
||||||
|
IDT[19].set_func(exception::simd);
|
||||||
|
IDT[20].set_func(exception::virtualization);
|
||||||
|
// 21 through 29 reserved
|
||||||
|
IDT[30].set_func(exception::security);
|
||||||
|
// 31 reserved
|
||||||
|
|
||||||
|
// Set up IRQs
|
||||||
|
IDT[32].set_func(irq::pit);
|
||||||
|
IDT[33].set_func(irq::keyboard);
|
||||||
|
IDT[34].set_func(irq::cascade);
|
||||||
|
IDT[35].set_func(irq::com2);
|
||||||
|
IDT[36].set_func(irq::com1);
|
||||||
|
IDT[37].set_func(irq::lpt2);
|
||||||
|
IDT[38].set_func(irq::floppy);
|
||||||
|
IDT[39].set_func(irq::lpt1);
|
||||||
|
IDT[40].set_func(irq::rtc);
|
||||||
|
IDT[41].set_func(irq::pci1);
|
||||||
|
IDT[42].set_func(irq::pci2);
|
||||||
|
IDT[43].set_func(irq::pci3);
|
||||||
|
IDT[44].set_func(irq::mouse);
|
||||||
|
IDT[45].set_func(irq::fpu);
|
||||||
|
IDT[46].set_func(irq::ata1);
|
||||||
|
IDT[47].set_func(irq::ata2);
|
||||||
|
|
||||||
|
// Set syscall function
|
||||||
|
IDT[0x80].set_func(syscall::syscall);
|
||||||
|
|
||||||
dtables::lidt(&IDTR);
|
dtables::lidt(&IDTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupt!(blank, {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt!(exception, {
|
|
||||||
println!("EXCEPTION");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt_error!(protection_fault, {
|
|
||||||
println!("PROTECTION FAULT");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt_error!(page_fault, {
|
|
||||||
println!("PAGE FAULT");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern fn syscall() {
|
|
||||||
extern {
|
|
||||||
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
let a;
|
|
||||||
let b;
|
|
||||||
let c;
|
|
||||||
let d;
|
|
||||||
let e;
|
|
||||||
let f;
|
|
||||||
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
|
|
||||||
: : : "intel", "volatile");
|
|
||||||
|
|
||||||
let a = syscall(a, b, c, d, e, f);
|
|
||||||
|
|
||||||
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
|
||||||
|
|
||||||
// Pop scratch registers, error code, and return
|
|
||||||
asm!("iretq" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub flags IdtFlags: u8 {
|
pub flags IdtFlags: u8 {
|
||||||
const IDT_PRESENT = 1 << 7,
|
const IDT_PRESENT = 1 << 7,
|
||||||
|
@ -142,4 +129,10 @@ impl IdtEntry {
|
||||||
self.offsetm = (base >> 16) as u16;
|
self.offsetm = (base >> 16) as u16;
|
||||||
self.offseth = (base >> 32) as u32;
|
self.offseth = (base >> 32) as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A function to set the offset more easily
|
||||||
|
pub fn set_func(&mut self, func: unsafe extern fn()) {
|
||||||
|
self.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||||
|
self.set_offset(8, func as usize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
//! Interrupt instructions
|
|
||||||
|
|
||||||
/// Clear interrupts
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn disable() {
|
|
||||||
asm!("cli" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set interrupts
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn enable() {
|
|
||||||
asm!("sti" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set interrupts and halt
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn enable_and_halt() {
|
|
||||||
asm!("sti
|
|
||||||
hlt"
|
|
||||||
: : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Halt instruction
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn halt() {
|
|
||||||
asm!("hlt" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pause instruction
|
|
||||||
/// Safe because it is similar to a NOP, and has no memory effects
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn pause() {
|
|
||||||
unsafe { asm!("pause" : : : : "intel", "volatile"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a stack trace
|
|
||||||
//TODO: Check for stack being mapped before dereferencing
|
|
||||||
#[inline(never)]
|
|
||||||
pub unsafe fn stack_trace() {
|
|
||||||
let mut rbp: usize;
|
|
||||||
asm!("xchg bx, bx" : "={rbp}"(rbp) : : : "intel", "volatile");
|
|
||||||
|
|
||||||
println!("TRACE: {:>016X}", rbp);
|
|
||||||
//Maximum 64 frames
|
|
||||||
for _frame in 0..64 {
|
|
||||||
let rip = *(rbp as *const usize).offset(1);
|
|
||||||
println!(" {:>016X}: {:>016X}", rbp, rip);
|
|
||||||
if rip == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rbp = *(rbp as *const usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// x86 External Interrupts (1-16).
|
|
||||||
pub static EXCEPTIONS: [Descriptor; 21] = [
|
|
||||||
Descriptor::new("Division error", Kind::Fault),
|
|
||||||
Descriptor::new("Debug trap", Kind::Trap),
|
|
||||||
Descriptor::new("Unmaskable interrupt", Kind::Unmaskable),
|
|
||||||
Descriptor::new("Breakpoint", Kind::Trap),
|
|
||||||
Descriptor::new("Overflow", Kind::Trap),
|
|
||||||
Descriptor::new("Out of bound", Kind::Fault),
|
|
||||||
Descriptor::new("Invalid opcode", Kind::Fault),
|
|
||||||
Descriptor::new("Device unavailable", Kind::Fault),
|
|
||||||
Descriptor::new("Double fault", Kind::Fault),
|
|
||||||
Descriptor::new("Coprocessor segment overrun", Kind::Fault),
|
|
||||||
Descriptor::new("Invalid TSS", Kind::Fault),
|
|
||||||
Descriptor::new("Segment not present", Kind::Fault),
|
|
||||||
Descriptor::new("Stack-segment fault", Kind::Fault),
|
|
||||||
Descriptor::new("General protection", Kind::Fault),
|
|
||||||
Descriptor::new("Page fault", Kind::Fault),
|
|
||||||
Descriptor::new("Reserved", Kind::Reserved),
|
|
||||||
Descriptor::new("x87 FPU", Kind::Fault),
|
|
||||||
Descriptor::new("Unaligned memory access", Kind::Fault),
|
|
||||||
Descriptor::new("Machine check", Kind::Abort),
|
|
||||||
Descriptor::new("SIMD floating-point", Kind::Fault),
|
|
||||||
Descriptor::new("Virtualization violation", Kind::Fault),
|
|
||||||
];
|
|
||||||
|
|
||||||
/// An interrupt description.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Descriptor {
|
|
||||||
/// The description of this interrupt.
|
|
||||||
pub desc: &'static str,
|
|
||||||
/// The interrupt type.
|
|
||||||
pub kind: Kind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Descriptor {
|
|
||||||
/// Create a new interrupt description.
|
|
||||||
pub const fn new(desc: &'static str, kind: Kind) -> Descriptor {
|
|
||||||
Descriptor {
|
|
||||||
desc: desc,
|
|
||||||
kind: kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The interrupt kind.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum Kind {
|
|
||||||
/// A fault.
|
|
||||||
///
|
|
||||||
/// This can have multiple sources, but is often a result of a program error of some sort.
|
|
||||||
Fault,
|
|
||||||
/// A trap.
|
|
||||||
///
|
|
||||||
/// These are often for debugging purposes.
|
|
||||||
Trap,
|
|
||||||
/// A deliberate abort.
|
|
||||||
Abort,
|
|
||||||
/// An unmaskable interrupt.
|
|
||||||
///
|
|
||||||
/// This is a forced interrupt which need to be handled immediately.
|
|
||||||
Unmaskable,
|
|
||||||
/// Reserved or deprecated.
|
|
||||||
Reserved,
|
|
||||||
}
|
|
97
arch/x86_64/src/interrupt/exception.rs
Normal file
97
arch/x86_64/src/interrupt/exception.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use super::halt;
|
||||||
|
|
||||||
|
interrupt!(divide_by_zero, {
|
||||||
|
print!("Divide by zero fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(debug, {
|
||||||
|
print!("Debug trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(non_maskable, {
|
||||||
|
print!("Non-maskable interrupt\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(breakpoint, {
|
||||||
|
print!("Breakpoint trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(overflow, {
|
||||||
|
print!("Overflow trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(bound_range, {
|
||||||
|
print!("Bound range exceeded fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(invalid_opcode, {
|
||||||
|
print!("Invalid opcode fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(device_not_available, {
|
||||||
|
print!("Device not available fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(double_fault, {
|
||||||
|
print!("Double fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(invalid_tss, {
|
||||||
|
print!("Invalid TSS fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(segment_not_present, {
|
||||||
|
print!("Segment not present fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(stack_segment, {
|
||||||
|
print!("Stack segment fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(protection, {
|
||||||
|
print!("Protection fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(page, {
|
||||||
|
print!("Page fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(fpu, {
|
||||||
|
print!("FPU floating point fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(alignment_check, {
|
||||||
|
print!("Alignment check fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(machine_check, {
|
||||||
|
print!("Machine check fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(simd, {
|
||||||
|
print!("SIMD floating point fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(virtualization, {
|
||||||
|
print!("Virtualization fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(security, {
|
||||||
|
print!("Security exception\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
98
arch/x86_64/src/interrupt/irq.rs
Normal file
98
arch/x86_64/src/interrupt/irq.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
use x86::io;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn master_ack() {
|
||||||
|
io::outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn slave_ack() {
|
||||||
|
io::outb(0xA0, 0x20);
|
||||||
|
master_ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt!(pit, {
|
||||||
|
io::outb(0x43, 0);
|
||||||
|
let low = io::inb(0x40);
|
||||||
|
let high = io::inb(0x40);
|
||||||
|
let count = (high as u16) << 8 | (low as u16);
|
||||||
|
let missed = 5370 - count;
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(keyboard, {
|
||||||
|
let data = io::inb(0x60);
|
||||||
|
print!("KEYBOARD {:X}\n", data);
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(cascade, {
|
||||||
|
print!("CASCADE\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(com2, {
|
||||||
|
print!("COM2\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(com1, {
|
||||||
|
print!("COM1\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(lpt2, {
|
||||||
|
print!("LPT2\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(floppy, {
|
||||||
|
print!("FLOPPY\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(lpt1, {
|
||||||
|
print!("LPT1\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(rtc, {
|
||||||
|
print!("RTC\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci1, {
|
||||||
|
print!("PCI1\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci2, {
|
||||||
|
print!("PCI2\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci3, {
|
||||||
|
print!("PCI3\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(mouse, {
|
||||||
|
let data = io::inb(0x60);
|
||||||
|
print!("MOUSE {:X}\n", data);
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(fpu, {
|
||||||
|
print!("FPU\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(ata1, {
|
||||||
|
print!("ATA1\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(ata2, {
|
||||||
|
print!("ATA2\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
57
arch/x86_64/src/interrupt/mod.rs
Normal file
57
arch/x86_64/src/interrupt/mod.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//! Interrupt instructions
|
||||||
|
|
||||||
|
pub mod exception;
|
||||||
|
pub mod irq;
|
||||||
|
pub mod syscall;
|
||||||
|
|
||||||
|
/// Clear interrupts
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn disable() {
|
||||||
|
asm!("cli" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interrupts
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn enable() {
|
||||||
|
asm!("sti" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interrupts and halt
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn enable_and_halt() {
|
||||||
|
asm!("sti
|
||||||
|
hlt"
|
||||||
|
: : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Halt instruction
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn halt() {
|
||||||
|
asm!("hlt" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pause instruction
|
||||||
|
/// Safe because it is similar to a NOP, and has no memory effects
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pause() {
|
||||||
|
unsafe { asm!("pause" : : : : "intel", "volatile"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a stack trace
|
||||||
|
//TODO: Check for stack being mapped before dereferencing
|
||||||
|
#[inline(never)]
|
||||||
|
pub unsafe fn stack_trace() {
|
||||||
|
let mut rbp: usize;
|
||||||
|
asm!("xchg bx, bx" : "={rbp}"(rbp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
println!("TRACE: {:>016X}", rbp);
|
||||||
|
//Maximum 64 frames
|
||||||
|
for _frame in 0..64 {
|
||||||
|
let rip = *(rbp as *const usize).offset(1);
|
||||||
|
println!(" {:>016X}: {:>016X}", rbp, rip);
|
||||||
|
if rip == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rbp = *(rbp as *const usize);
|
||||||
|
}
|
||||||
|
}
|
22
arch/x86_64/src/interrupt/syscall.rs
Normal file
22
arch/x86_64/src/interrupt/syscall.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn syscall() {
|
||||||
|
extern {
|
||||||
|
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a;
|
||||||
|
let b;
|
||||||
|
let c;
|
||||||
|
let d;
|
||||||
|
let e;
|
||||||
|
let f;
|
||||||
|
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
|
||||||
|
: : : "intel", "volatile");
|
||||||
|
|
||||||
|
let a = syscall(a, b, c, d, e, f);
|
||||||
|
|
||||||
|
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Pop scratch registers, error code, and return
|
||||||
|
asm!("iretq" : : : : "intel", "volatile");
|
||||||
|
}
|
|
@ -7,10 +7,12 @@ pub trait Io {
|
||||||
fn read(&self) -> Self::Value;
|
fn read(&self) -> Self::Value;
|
||||||
fn write(&mut self, value: Self::Value);
|
fn write(&mut self, value: Self::Value);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn readf(&self, flags: Self::Value) -> bool {
|
fn readf(&self, flags: Self::Value) -> bool {
|
||||||
(self.read() & flags) as Self::Value == flags
|
(self.read() & flags) as Self::Value == flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn writef(&mut self, flags: Self::Value, value: bool) {
|
fn writef(&mut self, flags: Self::Value, value: bool) {
|
||||||
let tmp: Self::Value = match value {
|
let tmp: Self::Value = match value {
|
||||||
true => self.read() | flags,
|
true => self.read() | flags,
|
||||||
|
@ -25,16 +27,18 @@ pub struct ReadOnly<I: Io> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Io> ReadOnly<I> {
|
impl<I: Io> ReadOnly<I> {
|
||||||
pub fn new(inner: I) -> ReadOnly<I> {
|
pub const fn new(inner: I) -> ReadOnly<I> {
|
||||||
ReadOnly {
|
ReadOnly {
|
||||||
inner: inner
|
inner: inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn read(&self) -> I::Value {
|
pub fn read(&self) -> I::Value {
|
||||||
self.inner.read()
|
self.inner.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn readf(&self, flags: I::Value) -> bool {
|
pub fn readf(&self, flags: I::Value) -> bool {
|
||||||
self.inner.readf(flags)
|
self.inner.readf(flags)
|
||||||
}
|
}
|
||||||
|
@ -45,16 +49,18 @@ pub struct WriteOnly<I: Io> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Io> WriteOnly<I> {
|
impl<I: Io> WriteOnly<I> {
|
||||||
pub fn new(inner: I) -> WriteOnly<I> {
|
pub const fn new(inner: I) -> WriteOnly<I> {
|
||||||
WriteOnly {
|
WriteOnly {
|
||||||
inner: inner
|
inner: inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn write(&mut self, value: I::Value) {
|
pub fn write(&mut self, value: I::Value) {
|
||||||
self.inner.write(value)
|
self.inner.write(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn writef(&mut self, flags: I::Value, value: bool) {
|
pub fn writef(&mut self, flags: I::Value, value: bool) {
|
||||||
self.inner.writef(flags, value)
|
self.inner.writef(flags, value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use x86::io;
|
||||||
|
|
||||||
use super::io::Io;
|
use super::io::Io;
|
||||||
|
|
||||||
|
@ -24,19 +25,15 @@ impl Io for Pio<u8> {
|
||||||
type Value = u8;
|
type Value = u8;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
let value: u8;
|
unsafe { io::inb(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u8) {
|
fn write(&mut self, value: u8) {
|
||||||
unsafe {
|
unsafe { io::outb(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,19 +42,15 @@ impl Io for Pio<u16> {
|
||||||
type Value = u16;
|
type Value = u16;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u16 {
|
fn read(&self) -> u16 {
|
||||||
let value: u16;
|
unsafe { io::inw(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u16) {
|
fn write(&mut self, value: u16) {
|
||||||
unsafe {
|
unsafe { io::outw(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,18 +59,14 @@ impl Io for Pio<u32> {
|
||||||
type Value = u32;
|
type Value = u32;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u32 {
|
fn read(&self) -> u32 {
|
||||||
let value: u32;
|
unsafe { io::inl(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u32) {
|
fn write(&mut self, value: u32) {
|
||||||
unsafe {
|
unsafe { io::outl(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,8 +124,8 @@ pub mod acpi;
|
||||||
/// Context switching
|
/// Context switching
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
|
||||||
/// Display handling
|
/// Devices
|
||||||
pub mod display;
|
pub mod device;
|
||||||
|
|
||||||
/// Memcpy, memmove, etc.
|
/// Memcpy, memmove, etc.
|
||||||
pub mod externs;
|
pub mod externs;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
|
||||||
|
|
||||||
use acpi;
|
use acpi;
|
||||||
use allocator::{HEAP_START, HEAP_SIZE};
|
use allocator::{HEAP_START, HEAP_SIZE};
|
||||||
use display;
|
use device;
|
||||||
use externs::memset;
|
use externs::memset;
|
||||||
use gdt;
|
use gdt;
|
||||||
use idt;
|
use idt;
|
||||||
|
@ -92,8 +92,8 @@ pub unsafe extern fn kstart() -> ! {
|
||||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize display
|
// Initialize devices
|
||||||
display::init(&mut active_table);
|
device::init(&mut active_table);
|
||||||
|
|
||||||
// Reset AP variables
|
// Reset AP variables
|
||||||
AP_COUNT.store(0, Ordering::SeqCst);
|
AP_COUNT.store(0, Ordering::SeqCst);
|
||||||
|
|
|
@ -151,13 +151,11 @@ pub unsafe fn switch() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(&mut *from_ptr).running = false;
|
(&mut *from_ptr).running = false;
|
||||||
(&mut *to_ptr).running = true;
|
(&mut *to_ptr).running = true;
|
||||||
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
|
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
|
||||||
|
|
||||||
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
|
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A context, which identifies either a process or a thread
|
/// A context, which identifies either a process or a thread
|
||||||
|
|
Loading…
Reference in a new issue