commit
7a68e4a177
@ -1,28 +0,0 @@
|
|||||||
use x86_64::structures::idt::Idt;
|
|
||||||
use spin::Once;
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
/// Alloc IDT at kernel heap, then init and load it.
|
|
||||||
pub fn init() {
|
|
||||||
let idt = Box::new({
|
|
||||||
use arch::interrupt::irq::*;
|
|
||||||
use consts::irq::*;
|
|
||||||
use arch::gdt::DOUBLE_FAULT_IST_INDEX;
|
|
||||||
|
|
||||||
let mut idt = Idt::new();
|
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
|
||||||
idt.double_fault.set_handler_fn(double_fault_handler);
|
|
||||||
idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(com1_handler);
|
|
||||||
idt[(T_IRQ0 + IRQ_COM2) as usize].set_handler_fn(com2_handler);
|
|
||||||
idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler);
|
|
||||||
idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler);
|
|
||||||
unsafe {
|
|
||||||
idt.page_fault.set_handler_fn(page_fault_handler)
|
|
||||||
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
|
|
||||||
}
|
|
||||||
idt
|
|
||||||
});
|
|
||||||
let idt = unsafe{ &*Box::into_raw(idt) };
|
|
||||||
|
|
||||||
idt.load();
|
|
||||||
}
|
|
@ -0,0 +1,105 @@
|
|||||||
|
// Following copied from crate `x86_64`
|
||||||
|
|
||||||
|
use core::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
pub struct Idt {
|
||||||
|
entries: [IdtEntry; 256],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Idt {
|
||||||
|
pub const fn new() -> Idt {
|
||||||
|
Idt {entries: [IdtEntry::new(); 256]}
|
||||||
|
}
|
||||||
|
pub fn load(&'static self) {
|
||||||
|
use x86_64::instructions::tables::{DescriptorTablePointer, lidt};
|
||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
let ptr = DescriptorTablePointer {
|
||||||
|
base: self as *const _ as u64,
|
||||||
|
limit: (size_of::<Self>() - 1) as u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe { lidt(&ptr) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<u8> for Idt {
|
||||||
|
type Output = IdtEntry;
|
||||||
|
fn index(&self, index: u8) -> &Self::Output {
|
||||||
|
&self.entries[index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<u8> for Idt {
|
||||||
|
fn index_mut(&mut self, index: u8) -> &mut Self::Output {
|
||||||
|
&mut self.entries[index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following copied from Redox
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct IdtFlags: u8 {
|
||||||
|
const PRESENT = 1 << 7;
|
||||||
|
const RING_0 = 0 << 5;
|
||||||
|
const RING_1 = 1 << 5;
|
||||||
|
const RING_2 = 2 << 5;
|
||||||
|
const RING_3 = 3 << 5;
|
||||||
|
const SS = 1 << 4;
|
||||||
|
const INTERRUPT = 0xE;
|
||||||
|
const TRAP = 0xF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct IdtEntry {
|
||||||
|
offsetl: u16,
|
||||||
|
selector: u16,
|
||||||
|
ist: u8,
|
||||||
|
attribute: u8,
|
||||||
|
offsetm: u16,
|
||||||
|
offseth: u32,
|
||||||
|
zero2: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdtEntry {
|
||||||
|
pub const fn new() -> IdtEntry {
|
||||||
|
IdtEntry {
|
||||||
|
offsetl: 0,
|
||||||
|
selector: 0,
|
||||||
|
ist: 0,
|
||||||
|
attribute: 0,
|
||||||
|
offsetm: 0,
|
||||||
|
offseth: 0,
|
||||||
|
zero2: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_flags(&mut self, flags: IdtFlags) -> &mut Self {
|
||||||
|
self.attribute = flags.bits;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_offset(&mut self, selector: u16, base: usize) -> &mut Self {
|
||||||
|
self.selector = selector;
|
||||||
|
self.offsetl = base as u16;
|
||||||
|
self.offsetm = (base >> 16) as u16;
|
||||||
|
self.offseth = (base >> 32) as u32;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// A function to set the offset more easily
|
||||||
|
pub fn set_handler_fn(&mut self, func: unsafe extern fn()) -> &mut Self {
|
||||||
|
self.set_flags(IdtFlags::PRESENT | IdtFlags::RING_0 | IdtFlags::INTERRUPT);
|
||||||
|
self.set_offset(8, func as usize);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self {
|
||||||
|
// The hardware IST index starts at 1, but our software IST index
|
||||||
|
// starts at 0. Therefore we need to add 1 here.
|
||||||
|
self.ist = (index + 1) as u8;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
use self::idt::*;
|
||||||
|
use spin::Once;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
mod idt;
|
||||||
|
|
||||||
|
/// Alloc IDT at kernel heap, then init and load it.
|
||||||
|
pub fn init() {
|
||||||
|
let idt = Box::new({
|
||||||
|
use arch::interrupt::{handler::*, consts::*};
|
||||||
|
use arch::gdt::DOUBLE_FAULT_IST_INDEX;
|
||||||
|
|
||||||
|
let mut idt = Idt::new();
|
||||||
|
idt[T_BRKPT].set_handler_fn(breakpoint);
|
||||||
|
idt[T_PGFLT].set_handler_fn(page_fault);
|
||||||
|
idt[T_GPFLT].set_handler_fn(general_protection_fault);
|
||||||
|
idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1);
|
||||||
|
idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2);
|
||||||
|
idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard);
|
||||||
|
idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer);
|
||||||
|
|
||||||
|
idt[T_SWITCH_TOU].set_handler_fn(to_user);
|
||||||
|
idt[T_SWITCH_TOK].set_handler_fn(to_kernel)
|
||||||
|
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
|
||||||
|
idt[T_SYSCALL].set_handler_fn(syscall)
|
||||||
|
.set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::TRAP);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
idt[T_DBLFLT].set_handler_fn(double_fault)
|
||||||
|
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
|
||||||
|
}
|
||||||
|
idt
|
||||||
|
});
|
||||||
|
let idt = unsafe{ &*Box::into_raw(idt) };
|
||||||
|
|
||||||
|
idt.load();
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
pub const T_DIVIDE : u8 = 0 ; // divide error
|
||||||
|
pub const T_DEBUG : u8 = 1 ; // debug exception
|
||||||
|
pub const T_NMI : u8 = 2 ; // non-maskable interrupt
|
||||||
|
pub const T_BRKPT : u8 = 3 ; // breakpoint
|
||||||
|
pub const T_OFLOW : u8 = 4 ; // overflow
|
||||||
|
pub const T_BOUND : u8 = 5 ; // bounds check
|
||||||
|
pub const T_ILLOP : u8 = 6 ; // illegal opcode
|
||||||
|
pub const T_DEVICE : u8 = 7 ; // device not available
|
||||||
|
pub const T_DBLFLT : u8 = 8 ; // double fault
|
||||||
|
pub const T_COPROC : u8 = 9 ; // reserved (not used since 486)
|
||||||
|
pub const T_TSS : u8 = 10; // invalid task switch segment
|
||||||
|
pub const T_SEGNP : u8 = 11; // segment not present
|
||||||
|
pub const T_STACK : u8 = 12; // stack exception
|
||||||
|
pub const T_GPFLT : u8 = 13; // general protection fault
|
||||||
|
pub const T_PGFLT : u8 = 14; // page fault
|
||||||
|
pub const T_RES : u8 = 15; // reserved
|
||||||
|
pub const T_FPERR : u8 = 16; // floating point error
|
||||||
|
pub const T_ALIGN : u8 = 17; // aligment check
|
||||||
|
pub const T_MCHK : u8 = 18; // machine check
|
||||||
|
pub const T_SIMDERR : u8 = 19; // SIMD floating point error
|
||||||
|
pub const T_IRQ0 : u8 = 32; // IRQ 0 corresponds to int T_IRQ
|
||||||
|
pub const IRQ_TIMER : u8 = 0;
|
||||||
|
pub const IRQ_KBD : u8 = 1;
|
||||||
|
pub const IRQ_COM2 : u8 = 3;
|
||||||
|
pub const IRQ_COM1 : u8 = 4;
|
||||||
|
pub const IRQ_IDE : u8 = 14;
|
||||||
|
pub const IRQ_ERROR : u8 = 19;
|
||||||
|
pub const IRQ_SPURIOUS : u8 = 31;
|
||||||
|
pub const T_SYSCALL : u8 = 0x80; // SYSCALL, ONLY FOR THIS PROJ
|
||||||
|
pub const T_SWITCH_TOU : u8 = 120; // user/kernel switch
|
||||||
|
pub const T_SWITCH_TOK : u8 = 121; // user/kernel switch
|
@ -1,73 +0,0 @@
|
|||||||
use x86_64::structures::idt::*;
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn breakpoint_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn double_fault_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame, _error_code: u64)
|
|
||||||
{
|
|
||||||
println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}\nErrorCode: {:#x}", stack_frame, _error_code);
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn page_fault_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode)
|
|
||||||
{
|
|
||||||
use x86_64::registers::control_regs::cr2;
|
|
||||||
println!("\nEXCEPTION: PAGE FAULT\n{:#?}\nErrorCode: {:#?}\nAddress: {:#x}",
|
|
||||||
stack_frame, error_code, cr2());
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "use_apic")]
|
|
||||||
use arch::driver::apic::ack;
|
|
||||||
#[cfg(not(feature = "use_apic"))]
|
|
||||||
use arch::driver::pic::ack;
|
|
||||||
|
|
||||||
use consts::irq::*;
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn keyboard_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
use arch::driver::keyboard;
|
|
||||||
println!("\nInterupt: Keyboard");
|
|
||||||
let c = keyboard::get();
|
|
||||||
println!("Key = '{}' {}", c as u8 as char, c);
|
|
||||||
ack(IRQ_KBD);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn com1_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
use arch::driver::serial::COM1;
|
|
||||||
println!("\nInterupt: COM1");
|
|
||||||
COM1.lock().receive();
|
|
||||||
ack(IRQ_COM1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn com2_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
use arch::driver::serial::COM2;
|
|
||||||
println!("\nInterupt: COM2");
|
|
||||||
COM2.lock().receive();
|
|
||||||
ack(IRQ_COM2);
|
|
||||||
}
|
|
||||||
|
|
||||||
use spin::Mutex;
|
|
||||||
static TICK: Mutex<usize> = Mutex::new(0);
|
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn timer_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
let mut tick = TICK.lock();
|
|
||||||
*tick += 1;
|
|
||||||
let tick = *tick;
|
|
||||||
if tick % 100 == 0 {
|
|
||||||
println!("\nInterupt: Timer\ntick = {}", tick);
|
|
||||||
}
|
|
||||||
ack(IRQ_TIMER);
|
|
||||||
}
|
|
@ -0,0 +1,452 @@
|
|||||||
|
//! Copy from Redox
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct ScratchRegisters {
|
||||||
|
pub r11: usize,
|
||||||
|
pub r10: usize,
|
||||||
|
pub r9: usize,
|
||||||
|
pub r8: usize,
|
||||||
|
pub rsi: usize,
|
||||||
|
pub rdi: usize,
|
||||||
|
pub rdx: usize,
|
||||||
|
pub rcx: usize,
|
||||||
|
pub rax: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScratchRegisters {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!("RAX: {:>016X}", { self.rax });
|
||||||
|
println!("RCX: {:>016X}", { self.rcx });
|
||||||
|
println!("RDX: {:>016X}", { self.rdx });
|
||||||
|
println!("RDI: {:>016X}", { self.rdi });
|
||||||
|
println!("RSI: {:>016X}", { self.rsi });
|
||||||
|
println!("R8: {:>016X}", { self.r8 });
|
||||||
|
println!("R9: {:>016X}", { self.r9 });
|
||||||
|
println!("R10: {:>016X}", { self.r10 });
|
||||||
|
println!("R11: {:>016X}", { self.r11 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! scratch_push {
|
||||||
|
() => (asm!(
|
||||||
|
"push rax
|
||||||
|
push rcx
|
||||||
|
push rdx
|
||||||
|
push rdi
|
||||||
|
push rsi
|
||||||
|
push r8
|
||||||
|
push r9
|
||||||
|
push r10
|
||||||
|
push r11"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! scratch_pop {
|
||||||
|
() => (asm!(
|
||||||
|
"pop r11
|
||||||
|
pop r10
|
||||||
|
pop r9
|
||||||
|
pop r8
|
||||||
|
pop rsi
|
||||||
|
pop rdi
|
||||||
|
pop rdx
|
||||||
|
pop rcx
|
||||||
|
pop rax"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct PreservedRegisters {
|
||||||
|
pub r15: usize,
|
||||||
|
pub r14: usize,
|
||||||
|
pub r13: usize,
|
||||||
|
pub r12: usize,
|
||||||
|
pub rbp: usize,
|
||||||
|
pub rbx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreservedRegisters {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!("RBX: {:>016X}", { self.rbx });
|
||||||
|
println!("RBP: {:>016X}", { self.rbp });
|
||||||
|
println!("R12: {:>016X}", { self.r12 });
|
||||||
|
println!("R13: {:>016X}", { self.r13 });
|
||||||
|
println!("R14: {:>016X}", { self.r14 });
|
||||||
|
println!("R15: {:>016X}", { self.r15 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! preserved_push {
|
||||||
|
() => (asm!(
|
||||||
|
"push rbx
|
||||||
|
push rbp
|
||||||
|
push r12
|
||||||
|
push r13
|
||||||
|
push r14
|
||||||
|
push r15"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! preserved_pop {
|
||||||
|
() => (asm!(
|
||||||
|
"pop r15
|
||||||
|
pop r14
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop rbp
|
||||||
|
pop rbx"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fs_push {
|
||||||
|
() => (asm!(
|
||||||
|
"push fs
|
||||||
|
mov rax, 0x18
|
||||||
|
mov fs, ax"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fs_pop {
|
||||||
|
() => (asm!(
|
||||||
|
"pop fs"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct IretRegisters {
|
||||||
|
pub rip: usize,
|
||||||
|
pub cs: usize,
|
||||||
|
pub rflags: usize,
|
||||||
|
pub rsp: usize,
|
||||||
|
pub ss: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IretRegisters {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!("SS: {:>016X}", { self.ss });
|
||||||
|
println!("RSP: {:>016X}", { self.rsp });
|
||||||
|
println!("RFLAG: {:>016X}", { self.rflags });
|
||||||
|
println!("CS: {:>016X}", { self.cs });
|
||||||
|
println!("RIP: {:>016X}", { self.rip });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! iret {
|
||||||
|
() => (asm!(
|
||||||
|
"iretq"
|
||||||
|
: : : : "intel", "volatile"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an interrupt function that can safely run rust code
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt {
|
||||||
|
($name:ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner() {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner();
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers and return
|
||||||
|
fs_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct InterruptStack {
|
||||||
|
pub fs: usize,
|
||||||
|
pub scratch: ScratchRegisters,
|
||||||
|
pub iret: IretRegisters,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptStack {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
self.iret.dump();
|
||||||
|
self.scratch.dump();
|
||||||
|
println!("FS: {:>016X}", { self.fs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_stack {
|
||||||
|
($name:ident, $stack: ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner($stack: &mut InterruptStack) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Get reference to stack variables
|
||||||
|
let rsp: usize;
|
||||||
|
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner(&mut *(rsp as *mut InterruptStack));
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers and return
|
||||||
|
fs_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct InterruptErrorStack {
|
||||||
|
pub fs: usize,
|
||||||
|
pub scratch: ScratchRegisters,
|
||||||
|
pub code: usize,
|
||||||
|
pub iret: IretRegisters,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptErrorStack {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
self.iret.dump();
|
||||||
|
println!("CODE: {:>016X}", { self.code });
|
||||||
|
self.scratch.dump();
|
||||||
|
println!("FS: {:>016X}", { self.fs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_error {
|
||||||
|
($name:ident, $stack:ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner($stack: &InterruptErrorStack) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Get reference to stack variables
|
||||||
|
let rsp: usize;
|
||||||
|
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner(&*(rsp as *const InterruptErrorStack));
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers, error code, and return
|
||||||
|
fs_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
asm!("add rsp, 8" : : : : "intel", "volatile");
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct InterruptStackP {
|
||||||
|
pub fs: usize,
|
||||||
|
pub preserved: PreservedRegisters,
|
||||||
|
pub scratch: ScratchRegisters,
|
||||||
|
pub iret: IretRegisters,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptStackP {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
self.iret.dump();
|
||||||
|
self.scratch.dump();
|
||||||
|
self.preserved.dump();
|
||||||
|
println!("FS: {:>016X}", { self.fs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::fmt::Debug;
|
||||||
|
use core::fmt::Formatter;
|
||||||
|
use core::fmt::Error;
|
||||||
|
|
||||||
|
impl Debug for InterruptStackP {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
self.dump();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_switch {
|
||||||
|
($name:ident, $rsp: ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner($rsp: &mut usize) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
preserved_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Get reference to stack variables
|
||||||
|
let mut rsp: usize;
|
||||||
|
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner(&mut rsp);
|
||||||
|
|
||||||
|
asm!("" : : "{rsp}"(rsp) : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers and return
|
||||||
|
fs_pop!();
|
||||||
|
preserved_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_stack_p {
|
||||||
|
($name:ident, $stack: ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner($stack: &mut InterruptStackP) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
preserved_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Get reference to stack variables
|
||||||
|
let rsp: usize;
|
||||||
|
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner(&mut *(rsp as *mut InterruptStackP));
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers and return
|
||||||
|
fs_pop!();
|
||||||
|
preserved_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct InterruptErrorStackP {
|
||||||
|
pub fs: usize,
|
||||||
|
pub preserved: PreservedRegisters,
|
||||||
|
pub scratch: ScratchRegisters,
|
||||||
|
pub code: usize,
|
||||||
|
pub iret: IretRegisters,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptErrorStackP {
|
||||||
|
pub fn dump(&self) {
|
||||||
|
self.iret.dump();
|
||||||
|
println!("CODE: {:>016X}", { self.code });
|
||||||
|
self.scratch.dump();
|
||||||
|
self.preserved.dump();
|
||||||
|
println!("FS: {:>016X}", { self.fs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_error_p {
|
||||||
|
($name:ident, $stack:ident, $func:block) => {
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn $name () {
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn inner($stack: &InterruptErrorStackP) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push scratch registers
|
||||||
|
scratch_push!();
|
||||||
|
preserved_push!();
|
||||||
|
fs_push!();
|
||||||
|
|
||||||
|
// Get reference to stack variables
|
||||||
|
let rsp: usize;
|
||||||
|
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Map kernel
|
||||||
|
// $crate::arch::x86_64::pti::map();
|
||||||
|
|
||||||
|
// Call inner rust function
|
||||||
|
inner(&*(rsp as *const InterruptErrorStackP));
|
||||||
|
|
||||||
|
// Unmap kernel
|
||||||
|
// $crate::arch::x86_64::pti::unmap();
|
||||||
|
|
||||||
|
// Pop scratch registers, error code, and return
|
||||||
|
fs_pop!();
|
||||||
|
preserved_pop!();
|
||||||
|
scratch_pop!();
|
||||||
|
asm!("add rsp, 8" : : : : "intel", "volatile");
|
||||||
|
iret!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
use arch::interrupt::consts::*;
|
||||||
|
|
||||||
|
pub fn switch_to_user() {
|
||||||
|
unsafe { int!(T_SWITCH_TOU); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_to_kernel() {
|
||||||
|
unsafe { int!(T_SWITCH_TOK); }
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
use super::*;
|
||||||
|
use memory::Stack;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Process {
|
||||||
|
pub(in process) pid: Pid,
|
||||||
|
name: &'static str,
|
||||||
|
kstack: Stack,
|
||||||
|
// page_table: Box<PageTable>,
|
||||||
|
pub(in process) status: Status,
|
||||||
|
pub(in process) rsp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Pid = usize;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Status {
|
||||||
|
Ready, Running, Sleeping(usize), Exited
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Process {
|
||||||
|
/// Make a new kernel thread
|
||||||
|
pub fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Self {
|
||||||
|
let kstack = mc.alloc_stack(7).unwrap();
|
||||||
|
let rsp = unsafe{ (kstack.top() as *mut TrapFrame).offset(-1) } as usize;
|
||||||
|
|
||||||
|
let tf = unsafe{ &mut *(rsp as *mut TrapFrame) };
|
||||||
|
*tf = TrapFrame::new_kernel_thread(entry, kstack.top());
|
||||||
|
|
||||||
|
Process {
|
||||||
|
pid: 0,
|
||||||
|
name,
|
||||||
|
kstack,
|
||||||
|
status: Status::Ready,
|
||||||
|
rsp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Make the first kernel thread `initproc`
|
||||||
|
/// Should be called only once
|
||||||
|
pub fn new_init(mc: &mut MemoryController) -> Self {
|
||||||
|
assert_has_not_been_called!();
|
||||||
|
Process {
|
||||||
|
pid: 0,
|
||||||
|
name: "init",
|
||||||
|
kstack: mc.kernel_stack.take().unwrap(),
|
||||||
|
status: Status::Running,
|
||||||
|
rsp: 0, // will be set at first schedule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
use alloc::BTreeMap;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Processor {
|
||||||
|
procs: BTreeMap<Pid, Process>,
|
||||||
|
current_pid: Pid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Processor {
|
||||||
|
pub fn new(mc: &mut MemoryController) -> Self {
|
||||||
|
Processor {
|
||||||
|
procs: BTreeMap::<Pid, Process>::new(),
|
||||||
|
current_pid: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_pid(&self) -> Pid {
|
||||||
|
let mut next: Pid = 0;
|
||||||
|
for &i in self.procs.keys() {
|
||||||
|
if i != next {
|
||||||
|
return next;
|
||||||
|
} else {
|
||||||
|
next = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, mut process: Process) {
|
||||||
|
let pid = self.alloc_pid();
|
||||||
|
process.pid = pid;
|
||||||
|
self.procs.insert(pid, process);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule(&mut self, rsp: &mut usize) {
|
||||||
|
let pid = self.find_next();
|
||||||
|
self.switch_to(pid, rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next(&self) -> Pid {
|
||||||
|
*self.procs.keys()
|
||||||
|
.find(|&&i| i > self.current_pid)
|
||||||
|
.unwrap_or(self.procs.keys().nth(0).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch_to(&mut self, pid: Pid, rsp: &mut usize) {
|
||||||
|
// for debug print
|
||||||
|
let pid0 = self.current_pid;
|
||||||
|
let rsp0 = *rsp;
|
||||||
|
|
||||||
|
if pid == self.current_pid {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let current = self.procs.get_mut(&self.current_pid).unwrap();
|
||||||
|
current.status = Status::Ready;
|
||||||
|
current.rsp = *rsp;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let process = self.procs.get_mut(&pid).unwrap();
|
||||||
|
process.status = Status::Running;
|
||||||
|
*rsp = process.rsp;
|
||||||
|
// TODO switch page table
|
||||||
|
}
|
||||||
|
self.current_pid = pid;
|
||||||
|
debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue