Merge branch 'process' into dev

master
WangRunji 7 years ago
commit 7a68e4a177

@ -6,7 +6,7 @@
use syscall::io::{Io, Mmio};
use bit_field::BitField;
use consts::irq::T_IRQ0;
use arch::interrupt::consts::T_IRQ0;
use spin::Mutex;
pub fn init(ioapic_id: u8)

@ -1,7 +1,7 @@
pub fn init() {
assert_has_not_been_called!("keyboard::init must be called only once");
use consts::irq::*;
use arch::interrupt::consts::*;
use arch::interrupt::enable_irq;
enable_irq(IRQ_KBD);
}

@ -12,8 +12,7 @@ pub fn init() {
COM1.lock().init();
COM2.lock().init();
use consts::irq::*;
use arch::interrupt::enable_irq;
use arch::interrupt::{enable_irq, consts::{IRQ_COM1, IRQ_COM2}};
enable_irq(IRQ_COM1);
enable_irq(IRQ_COM2);
}

@ -5,6 +5,7 @@ use x86_64::structures::gdt::SegmentSelector;
use x86_64::{PrivilegeLevel, VirtualAddress};
use spin::Once;
use alloc::boxed::Box;
use core::ptr::Unique;
/// Alloc TSS & GDT at kernel heap, then init and load it.
/// The double fault stack will be allocated at kernel heap too.
@ -13,32 +14,28 @@ pub fn init() {
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::load_tss;
struct DoubleFaultStack {
space: [u8; 4096]
}
let double_fault_stack_top = Box::into_raw(Box::new(
DoubleFaultStack{space: [0; 4096]}
)) as usize + 4096;
let double_fault_stack_top = Box::into_raw(Box::new([0u8; 4096])) as usize + 4096;
debug!("Double fault stack top @ {:#x}", double_fault_stack_top);
let mut tss = Box::new({
let mut tss = TaskStateSegment::new();
// 设置 Double Fault 时,自动切换栈的地址
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX]
= VirtualAddress(double_fault_stack_top);
tss
});
let tss = unsafe{ &*Box::into_raw(tss) };
unsafe{ TSS_PTR = Unique::new_unchecked(Box::into_raw(tss)); }
let tss = unsafe{ TSS_PTR.as_ref() };
let mut code_selector = SegmentSelector(0);
let mut tss_selector = SegmentSelector(0);
let gdt = Box::new({
let mut gdt = Gdt::new();
gdt.add_entry(GNULL);
code_selector =
gdt.add_entry(KCODE);
gdt.add_entry(UCODE);
gdt.add_entry(KDATA);
gdt.add_entry(UDATA);
tss_selector = gdt.add_entry(Descriptor::tss_segment(&tss));
gdt.add_entry(Descriptor::tss_segment(&tss));
gdt
});
let gdt = unsafe{ &*Box::into_raw(gdt) };
@ -46,21 +43,41 @@ pub fn init() {
unsafe {
// reload code segment register
set_cs(code_selector);
set_cs(KCODE_SELECTOR);
// load TSS
load_tss(tss_selector);
load_tss(TSS_SELECTOR);
}
}
// TODO: more elegant?
static mut TSS_PTR: Unique<TaskStateSegment> = unsafe{ Unique::new_unchecked(0 as *mut _) };
/// 设置从Ring3跳到Ring0时自动切换栈的地址
///
/// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态
pub fn set_ring0_rsp(rsp: usize) {
debug!("gdt.set_ring0_rsp: {:#x}", rsp);
unsafe {
TSS_PTR.as_mut().privilege_stack_table[0] = VirtualAddress(rsp);
// debug!("TSS:\n{:?}", TSS_PTR.as_ref());
}
}
pub const DOUBLE_FAULT_IST_INDEX: usize = 0;
// Copied from xv6 x86_64
const GNULL: Descriptor = Descriptor::UserSegment(0);
const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE
const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3);
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring0);
pub struct Gdt {
table: [u64; 8],
next_free: usize,

@ -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

@ -0,0 +1,99 @@
#[macro_use]
#[path = "./template.rs"]
mod template;
use self::template::*;
pub type TrapFrame = InterruptStackP;
interrupt_stack!(breakpoint, stack, {
println!("\nEXCEPTION: Breakpoint");
stack.dump();
});
interrupt_error_p!(double_fault, stack, {
println!("\nEXCEPTION: Double Fault");
stack.dump();
loop {}
});
interrupt_error_p!(page_fault, stack, {
use x86_64::registers::control_regs::cr2;
println!("\nEXCEPTION: Page Fault\nAddress: {:#x}", cr2());
stack.dump();
loop {}
});
interrupt_error_p!(general_protection_fault, stack, {
println!("\nEXCEPTION: General Protection Fault");
stack.dump();
loop {}
});
#[cfg(feature = "use_apic")]
use arch::driver::apic::ack;
#[cfg(not(feature = "use_apic"))]
use arch::driver::pic::ack;
use super::consts::*;
interrupt!(keyboard, {
use arch::driver::keyboard;
println!("\nInterupt: Keyboard");
let c = keyboard::get();
println!("Key = '{}' {}", c as u8 as char, c);
ack(IRQ_KBD);
});
interrupt!(com1, {
use arch::driver::serial::COM1;
println!("\nInterupt: COM1");
COM1.lock().receive();
ack(IRQ_COM1);
});
interrupt!(com2, {
use arch::driver::serial::COM2;
println!("\nInterupt: COM2");
COM2.lock().receive();
ack(IRQ_COM2);
});
use spin::Mutex;
// FIXME: Deadlock
//static TICK: Mutex<usize> = Mutex::new(0);
interrupt_switch!(timer, rsp, {
// let mut tick = TICK.lock();
// *tick += 1;
// let tick = *tick;
static mut tick: usize = 0;
unsafe{ tick += 1; }
if tick % 100 == 0 {
println!("\nInterupt: Timer\ntick = {}", tick);
use process;
process::schedule(rsp);
}
ack(IRQ_TIMER);
});
interrupt_stack_p!(to_user, stack, {
use arch::gdt;
println!("\nInterupt: To User");
let rsp = unsafe{ (stack as *const InterruptStackP).offset(1) } as usize;
gdt::set_ring0_rsp(rsp);
stack.iret.cs = gdt::UCODE_SELECTOR.0 as usize;
stack.iret.ss = gdt::UDATA_SELECTOR.0 as usize;
stack.iret.rflags |= 3 << 12; // 设置EFLAG的I/O特权位使得在用户态可使用in/out指令
});
interrupt_stack_p!(to_kernel, stack, {
// println!("rsp @ {:#x}", stack as *const _ as usize);
use arch::gdt;
println!("\nInterupt: To Kernel");
stack.iret.cs = gdt::KCODE_SELECTOR.0 as usize;
stack.iret.ss = gdt::KDATA_SELECTOR.0 as usize;
});
interrupt_stack_p!(syscall, stack, {
println!("\nInterupt: Syscall");
});

@ -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);
}

@ -1,7 +1,23 @@
use x86_64;
use arch::driver::{apic::IOAPIC, pic};
pub mod irq;
pub mod handler;
pub mod consts;
pub use self::handler::TrapFrame;
impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self {
use arch::gdt;
let mut tf = TrapFrame::default();
tf.iret.cs = gdt::KCODE_SELECTOR.0 as usize;
tf.iret.rip = entry as usize;
tf.iret.ss = gdt::KDATA_SELECTOR.0 as usize;
tf.iret.rsp = rsp;
tf.iret.rflags = 0x282;
tf
}
}
#[inline(always)]
pub unsafe fn enable() {

@ -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!();
}
};
}

@ -5,3 +5,4 @@ pub mod paging;
pub mod gdt;
pub mod idt;
pub mod smp;
pub mod syscall;

@ -78,7 +78,8 @@ impl Mapper {
let mut p1 = p2.next_table_create(page.p2_index(), allocator);
assert!(p1[page.p1_index()].is_unused());
p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT);
// TODO: Remove USER_ACCESSIBLE
p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE);
}
pub fn map<A>(&mut self, page: Page, flags: EntryFlags, allocator: &mut A)

@ -50,7 +50,8 @@ impl<L> Table<L> where L: HierarchicalLevel {
assert!(!self.entries[index].flags().contains(EntryFlags::HUGE_PAGE),
"mapping code does not support huge pages");
let frame = allocator.allocate_frame().expect("no frames available");
self.entries[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE);
// TODO: Remove USER_ACCESSIBLE
self.entries[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::USER_ACCESSIBLE);
self.next_table_mut(index).unwrap().zero();
}
self.next_table_mut(index).unwrap()

@ -19,8 +19,12 @@ pub fn start_other_cores(acpi: &ACPI_Result, mc: &mut MemoryController) {
let page_table = unsafe{ *(0xFFFF_FFFF_FFFF_FFF8 as *const u32) } & 0xFFFF_F000;
for i in 1 .. acpi.cpu_num {
let apic_id = acpi.cpu_acpi_ids[i as usize];
let kstack = mc.alloc_stack(7).unwrap();
let kstack_top = kstack.top() as u64;
use core::mem::forget;
forget(kstack); // TODO pass this kstack to new AP
*args = EntryArgs {
kstack: mc.alloc_stack(7).unwrap().top() as u64,
kstack: kstack_top,
page_table: page_table,
stack: 0x8000, // just enough stack to get us to entry64mp
};

@ -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); }
}

@ -94,14 +94,3 @@ pub const MAX_CPU_NUM: usize = 8;
/// Offset for usage in other temporary pages
pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE;
pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK)/PML4_SIZE;
pub mod irq {
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;
}

@ -30,11 +30,14 @@ use arch::driver::vga::Color;
fn print_in_color(args: fmt::Arguments, color: Color) {
use core::fmt::Write;
use arch::driver::vga::*;
{
let mut writer = vga_writer::VGA_WRITER.lock();
writer.set_color(color);
writer.write_fmt(args).unwrap();
}
// {
// let mut writer = vga_writer::VGA_WRITER.lock();
// writer.set_color(color);
// writer.write_fmt(args).unwrap();
// }
// TODO: 解决死锁问题
// 若进程在持有锁时被中断,中断处理程序请求输出,就会死锁
unsafe{ COM1.force_unlock(); }
COM1.lock().write_fmt(args).unwrap();
}

@ -9,6 +9,8 @@
#![feature(abi_x86_interrupt)]
#![feature(iterator_step_by)]
#![feature(unboxed_closures)]
#![feature(naked_functions)]
#![feature(asm)]
#![no_std]
@ -21,6 +23,7 @@ extern crate spin;
extern crate multiboot2;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate x86_64;
#[macro_use]
extern crate once;
@ -35,9 +38,10 @@ mod io;
mod memory;
mod lang;
mod util;
#[macro_use] // test!
mod test_util;
#[macro_use]
mod macros;
mod consts;
mod process;
#[allow(dead_code)]
#[cfg(target_arch = "x86_64")]
@ -71,10 +75,32 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
let acpi = arch::driver::init(
|addr: usize| memory_controller.map_page_identity(addr));
// memory_controller.print_page_table();
arch::smp::start_other_cores(&acpi, &mut memory_controller);
// FIXME: 开启SMP后导致switch_to_user中设置rsp无效
// arch::smp::start_other_cores(&acpi, &mut memory_controller);
process::init(&mut memory_controller);
unsafe{ arch::interrupt::enable(); }
loop{}
unsafe{
use arch::syscall;
// 在用户模式下触发时钟中断会导致GPF
// (可能是由于没有合理分离栈)
no_interrupt!({
syscall::switch_to_user();
println!("Now in user mode");
syscall::switch_to_kernel();
println!("Now in kernel mode");
});
}
loop{
println!("init ...");
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
test_end!();
unreachable!();
@ -89,7 +115,7 @@ pub extern "C" fn other_main() -> ! {
let cpu_id = arch::driver::apic::lapic_id();
println!("Hello world! from CPU {}!", arch::driver::apic::lapic_id());
unsafe{ arch::smp::notify_started(cpu_id); }
unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault
// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault
loop {}
}

@ -23,3 +23,12 @@ macro_rules! test {
}
)
}
macro_rules! no_interrupt {
{$func:block} => {
use arch::interrupt;
unsafe{ interrupt::disable(); }
$func;
unsafe{ interrupt::enable(); }
};
}

@ -46,7 +46,7 @@ pub fn init(boot_info: &BootInformation) -> MemoryController {
boot_info_start, boot_info_end,
memory_map_tag.memory_areas());
let mut active_table = remap_the_kernel(&mut frame_allocator, boot_info);
let (mut active_table, kernel_stack) = remap_the_kernel(&mut frame_allocator, boot_info);
use self::paging::Page;
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
@ -67,14 +67,15 @@ pub fn init(boot_info: &BootInformation) -> MemoryController {
};
MemoryController {
active_table: active_table,
frame_allocator: frame_allocator,
stack_allocator: stack_allocator,
kernel_stack: Some(kernel_stack),
active_table,
frame_allocator,
stack_allocator,
}
}
pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
-> ActivePageTable
-> (ActivePageTable, Stack)
where A: FrameAllocator
{
let mut temporary_page = TemporaryPage::new(Page::containing_address(0xcafebabe), allocator);
@ -137,12 +138,14 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
let stack_bottom = PhysicalAddress(stack_bottom as u64).to_kernel_virtual();
let stack_bottom_page = Page::containing_address(stack_bottom);
active_table.unmap(stack_bottom_page, allocator);
let kernel_stack = Stack::new(stack_bottom + 8 * PAGE_SIZE, stack_bottom + 1 * PAGE_SIZE);
println!("guard page at {:#x}", stack_bottom_page.start_address());
active_table
(active_table, kernel_stack)
}
pub struct MemoryController {
pub kernel_stack: Option<Stack>,
active_table: paging::ActivePageTable,
frame_allocator: AreaFrameAllocator,
stack_allocator: stack_allocator::StackAllocator,
@ -150,7 +153,8 @@ pub struct MemoryController {
impl MemoryController {
pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option<Stack> {
let &mut MemoryController { ref mut active_table,
let &mut MemoryController { ref mut kernel_stack,
ref mut active_table,
ref mut frame_allocator,
ref mut stack_allocator } = self;
stack_allocator.alloc_stack(active_table, frame_allocator,

@ -61,7 +61,7 @@ pub struct Stack {
}
impl Stack {
fn new(top: usize, bottom: usize) -> Stack {
pub(super) fn new(top: usize, bottom: usize) -> Stack {
assert!(top > bottom);
Stack {
top: top,
@ -77,3 +77,9 @@ impl Stack {
self.bottom
}
}
impl Drop for Stack {
fn drop(&mut self) {
panic!("stack leak: {:#x?}", self);
}
}

@ -0,0 +1,45 @@
use memory::MemoryController;
use spin::{Once, Mutex};
use self::process::*;
use self::processor::*;
mod process;
mod processor;
/// 平台相关依赖struct TrapFrame
///
/// ## 必须实现的特性
///
/// * Debug: 用于Debug输出
use arch::interrupt::TrapFrame;
pub fn init(mc: &mut MemoryController) {
PROCESSOR.call_once(|| {Mutex::new({
let mut processor = Processor::new(mc);
let initproc = Process::new_init(mc);
let idleproc = Process::new("idle", idle_thread, mc);
processor.add(initproc);
processor.add(idleproc);
processor
})});
}
static PROCESSOR: Once<Mutex<Processor>> = Once::new();
/// Called by timer handler in arch
/// 设置rsp指向接下来要执行线程的 内核栈顶
/// 之后中断处理例程会重置rsp恢复对应线程的上下文
pub fn schedule(rsp: &mut usize) {
PROCESSOR.try().unwrap().lock().schedule(rsp);
}
extern fn idle_thread() {
loop {
println!("idle ...");
let mut i = 0;
while i < 1 << 22 {
i += 1;
}
}
}

@ -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…
Cancel
Save