diff --git a/Cargo.toml b/Cargo.toml index 810fe889..d12052ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ once = "0.3.2" rlibc = "0.1.4" spin = "0.4.5" volatile = "0.1.0" +x86_64 = "0.1.0" [dependencies.hole_list_allocator] path = "libs/hole_list_allocator" @@ -19,9 +20,6 @@ path = "libs/hole_list_allocator" features = ["spin_no_std"] version = "0.2.1" -[dependencies.x86] -default-features = false -version = "0.8.0" [lib] crate-type = ["staticlib"] diff --git a/src/interrupts/gdt.rs b/src/interrupts/gdt.rs index d0259a97..23400821 100644 --- a/src/interrupts/gdt.rs +++ b/src/interrupts/gdt.rs @@ -1,6 +1,6 @@ -use x86::bits64::task::TaskStateSegment; -use x86::shared::segmentation::SegmentSelector; -use x86::shared::PrivilegeLevel; +use x86_64::structures::tss::TaskStateSegment; +use x86_64::structures::gdt::SegmentSelector; +use x86_64::PrivilegeLevel; pub struct Gdt { table: [u64; 8], @@ -39,12 +39,11 @@ impl Gdt { } pub fn load(&'static self) { - use x86::shared::dtables::{DescriptorTablePointer, lgdt}; - use x86::shared::segmentation; + use x86_64::instructions::tables::{DescriptorTablePointer, lgdt}; use core::mem::size_of; let ptr = DescriptorTablePointer { - base: self.table.as_ptr() as *const segmentation::SegmentDescriptor, + base: self.table.as_ptr() as u64, limit: (self.table.len() * size_of::() - 1) as u16, }; diff --git a/src/interrupts/idt.rs b/src/interrupts/idt.rs deleted file mode 100644 index 33cb8c30..00000000 --- a/src/interrupts/idt.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use x86::shared::segmentation::{self, SegmentSelector}; -use x86::shared::PrivilegeLevel; - -pub struct Idt([Entry; 16]); - -impl Idt { - pub fn new() -> Idt { - Idt([Entry::missing(); 16]) - } - - pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions { - self.0[entry as usize] = Entry::new(segmentation::cs(), handler); - &mut self.0[entry as usize].options - } - - pub fn load(&'static self) { - use x86::shared::dtables::{DescriptorTablePointer, lidt}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self as *const _ as *const ::x86::bits64::irq::IdtEntry, - limit: (size_of::() - 1) as u16, - }; - - unsafe { lidt(&ptr) }; - } -} - -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct Entry { - pointer_low: u16, - gdt_selector: SegmentSelector, - options: EntryOptions, - pointer_middle: u16, - pointer_high: u32, - reserved: u32, -} - -pub type HandlerFunc = extern "C" fn() -> !; - -impl Entry { - fn new(gdt_selector: SegmentSelector, handler: HandlerFunc) -> Self { - let pointer = handler as u64; - Entry { - gdt_selector: gdt_selector, - pointer_low: pointer as u16, - pointer_middle: (pointer >> 16) as u16, - pointer_high: (pointer >> 32) as u32, - options: EntryOptions::new(), - reserved: 0, - } - } - - fn missing() -> Self { - Entry { - gdt_selector: SegmentSelector::new(0, PrivilegeLevel::Ring0), - pointer_low: 0, - pointer_middle: 0, - pointer_high: 0, - options: EntryOptions::minimal(), - reserved: 0, - } - } -} - -use bit_field::BitField; - -#[derive(Debug, Clone, Copy)] -pub struct EntryOptions(u16); - -impl EntryOptions { - fn minimal() -> Self { - let mut options = 0; - options.set_bits(9..12, 0b111); // 'must-be-one' bits - EntryOptions(options) - } - - fn new() -> Self { - let mut options = Self::minimal(); - options.set_present(true).disable_interrupts(true); - options - } - - pub fn set_present(&mut self, present: bool) -> &mut Self { - self.0.set_bit(15, present); - self - } - - pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self { - self.0.set_bit(8, !disable); - self - } - - #[allow(dead_code)] - pub fn set_privilege_level(&mut self, dpl: u16) -> &mut Self { - self.0.set_bits(13..15, dpl); - self - } - - pub 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.0.set_bits(0..3, index + 1); - self - } -} diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs index b5a5d131..13a5253e 100644 --- a/src/interrupts/mod.rs +++ b/src/interrupts/mod.rs @@ -8,101 +8,27 @@ // except according to those terms. use memory::MemoryController; -use x86::bits64::task::TaskStateSegment; +use x86_64::structures::tss::TaskStateSegment; +use x86_64::structures::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode}; use spin::Once; -mod idt; mod gdt; -macro_rules! save_scratch_registers { - () => { - asm!("push rax - push rcx - push rdx - push rsi - push rdi - push r8 - push r9 - push r10 - push r11 - " :::: "intel", "volatile"); - } -} - -macro_rules! restore_scratch_registers { - () => { - asm!("pop r11 - pop r10 - pop r9 - pop r8 - pop rdi - pop rsi - pop rdx - pop rcx - pop rax - " :::: "intel", "volatile"); - } -} - -macro_rules! handler { - ($name: ident) => {{ - #[naked] - extern "C" fn wrapper() -> ! { - unsafe { - save_scratch_registers!(); - asm!("mov rdi, rsp - add rdi, 9*8 // calculate exception stack frame pointer - call $0" - :: "i"($name as extern "C" fn( - &ExceptionStackFrame)) - : "rdi" : "intel"); - - restore_scratch_registers!(); - asm!("iretq" :::: "intel", "volatile"); - ::core::intrinsics::unreachable(); - } - } - wrapper - }} -} - -macro_rules! handler_with_error_code { - ($name: ident) => {{ - #[naked] - extern "C" fn wrapper() -> ! { - unsafe { - save_scratch_registers!(); - asm!("mov rsi, [rsp + 9*8] // load error code into rsi - mov rdi, rsp - add rdi, 10*8 // calculate exception stack frame pointer - sub rsp, 8 // align the stack pointer - call $0 - add rsp, 8 // undo stack pointer alignment - " :: "i"($name as extern "C" fn( - &ExceptionStackFrame, u64)) - : "rdi","rsi" : "intel"); - restore_scratch_registers!(); - asm!("add rsp, 8 // pop error code - iretq" :::: "intel", "volatile"); - ::core::intrinsics::unreachable(); - } - } - wrapper - }} -} - const DOUBLE_FAULT_IST_INDEX: usize = 0; lazy_static! { - static ref IDT: idt::Idt = { - let mut idt = idt::Idt::new(); + static ref IDT: Idt = { + let mut idt = Idt::new(); - idt.set_handler(0, handler!(divide_by_zero_handler)); - idt.set_handler(3, handler!(breakpoint_handler)); - idt.set_handler(6, handler!(invalid_opcode_handler)); - idt.set_handler(8, handler_with_error_code!(double_fault_handler)) - .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - idt.set_handler(14, handler_with_error_code!(page_fault_handler)); + idt.divide_by_zero.set_handler_fn(divide_by_zero_handler); + idt.breakpoint.set_handler_fn(breakpoint_handler); + idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); + idt.page_fault.set_handler_fn(page_fault_handler); + + unsafe { + idt.double_fault.set_handler_fn(double_fault_handler) + .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); + } idt }; @@ -112,20 +38,22 @@ static TSS: Once = Once::new(); static GDT: Once = Once::new(); pub fn init(memory_controller: &mut MemoryController) { - use x86::shared::segmentation::{SegmentSelector, set_cs}; - use x86::shared::task::load_tr; + use x86_64::structures::gdt::SegmentSelector; + use x86_64::instructions::segmentation::set_cs; + use x86_64::instructions::tables::load_tss; + use x86_64::VirtualAddress; let double_fault_stack = memory_controller.alloc_stack(1).expect("could not allocate double fault stack"); let tss = TSS.call_once(|| { let mut tss = TaskStateSegment::new(); - tss.ist[DOUBLE_FAULT_IST_INDEX] = double_fault_stack.top() as u64; + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = VirtualAddress(double_fault_stack.top()); tss }); - let mut code_selector = SegmentSelector::empty(); - let mut tss_selector = SegmentSelector::empty(); + let mut code_selector = SegmentSelector(0); + let mut tss_selector = SegmentSelector(0); let gdt = GDT.call_once(|| { let mut gdt = gdt::Gdt::new(); code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment()); @@ -138,61 +66,41 @@ pub fn init(memory_controller: &mut MemoryController) { // reload code segment register set_cs(code_selector); // load TSS - load_tr(tss_selector); + load_tss(tss_selector); } IDT.load(); } -#[derive(Debug)] -#[repr(C)] -struct ExceptionStackFrame { - instruction_pointer: u64, - code_segment: u64, - cpu_flags: u64, - stack_pointer: u64, - stack_segment: u64, -} - -extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) { +extern "x86-interrupt" fn divide_by_zero_handler(stack_frame: &mut ExceptionStackFrame) { println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame); loop {} } -extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) { +extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut ExceptionStackFrame) { println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}", stack_frame.instruction_pointer, stack_frame); } -extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) { +extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: &mut ExceptionStackFrame) { println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}", stack_frame.instruction_pointer, stack_frame); loop {} } -bitflags! { - flags PageFaultErrorCode: u64 { - const PROTECTION_VIOLATION = 1 << 0, - const CAUSED_BY_WRITE = 1 << 1, - const USER_MODE = 1 << 2, - const MALFORMED_TABLE = 1 << 3, - const INSTRUCTION_FETCH = 1 << 4, - } -} - -extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) { - use x86::shared::control_regs; +extern "x86-interrupt" fn page_fault_handler(stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode) { + use x86_64::registers::control_regs; println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \ {:?}\n{:#?}", - unsafe { control_regs::cr2() }, - PageFaultErrorCode::from_bits(error_code).unwrap(), + control_regs::cr2(), + error_code, stack_frame); loop {} } -extern "C" fn double_fault_handler(stack_frame: &ExceptionStackFrame, _error_code: u64) { +extern "x86-interrupt" fn double_fault_handler(stack_frame: &mut ExceptionStackFrame, _error_code: u64) { println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); loop {} } diff --git a/src/lib.rs b/src/lib.rs index 07e14fab..2afc3004 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ #![feature(alloc, collections)] #![feature(asm)] #![feature(naked_functions)] -#![feature(core_intrinsics)] +#![feature(abi_x86_interrupt)] #![no_std] extern crate rlibc; @@ -21,8 +21,7 @@ extern crate spin; extern crate multiboot2; #[macro_use] extern crate bitflags; -#[macro_use] -extern crate x86; +extern crate x86_64; #[macro_use] extern crate once; extern crate bit_field; @@ -68,7 +67,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) { } fn enable_nxe_bit() { - use x86::shared::msr::{IA32_EFER, rdmsr, wrmsr}; + use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr}; let nxe_bit = 1 << 11; unsafe { @@ -78,9 +77,9 @@ fn enable_nxe_bit() { } fn enable_write_protect_bit() { - use x86::shared::control_regs::{cr0, cr0_write, CR0_WRITE_PROTECT}; + use x86_64::registers::control_regs::{cr0, cr0_write, Cr0}; - unsafe { cr0_write(cr0() | CR0_WRITE_PROTECT) }; + unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) }; } #[cfg(not(test))] diff --git a/src/memory/paging/mapper.rs b/src/memory/paging/mapper.rs index d6b2500e..b954279c 100644 --- a/src/memory/paging/mapper.rs +++ b/src/memory/paging/mapper.rs @@ -105,6 +105,9 @@ impl Mapper { pub fn unmap(&mut self, page: Page, allocator: &mut A) where A: FrameAllocator { + use x86_64::VirtualAddress; + use x86_64::instructions::tlb; + assert!(self.translate(page.start_address()).is_some()); let p1 = self.p4_mut() @@ -114,7 +117,7 @@ impl Mapper { .expect("mapping code does not support huge pages"); let frame = p1[page.p1_index()].pointed_frame().unwrap(); p1[page.p1_index()].set_unused(); - unsafe { ::x86::shared::tlb::flush(page.start_address()) }; + tlb::flush(VirtualAddress(page.start_address())); // TODO free p(1,2,3) table if empty // allocator.deallocate_frame(frame); } diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs index 276a0d27..ba23c269 100644 --- a/src/memory/paging/mod.rs +++ b/src/memory/paging/mod.rs @@ -119,38 +119,39 @@ impl ActivePageTable { f: F) where F: FnOnce(&mut Mapper) { - use x86::shared::{control_regs, tlb}; - let flush_tlb = || unsafe { tlb::flush_all() }; + use x86_64::registers::control_regs; + use x86_64::instructions::tlb; { - let backup = Frame::containing_address(unsafe { control_regs::cr3() } as usize); + let backup = Frame::containing_address(control_regs::cr3().0 as usize); // map temporary_page to current p4 table let p4_table = temporary_page.map_table_frame(backup.clone(), self); // overwrite recursive mapping self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE); - flush_tlb(); + tlb::flush_all(); // execute f in the new context f(self); // restore recursive mapping to original p4 table p4_table[511].set(backup, PRESENT | WRITABLE); - flush_tlb(); + tlb::flush_all(); } temporary_page.unmap(self); } pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { - use x86::shared::control_regs; + use x86_64::PhysicalAddress; + use x86_64::registers::control_regs; let old_table = InactivePageTable { - p4_frame: Frame::containing_address(unsafe { control_regs::cr3() } as usize), + p4_frame: Frame::containing_address(control_regs::cr3().0 as usize), }; unsafe { - control_regs::cr3_write(new_table.p4_frame.start_address()); + control_regs::cr3_write(PhysicalAddress(new_table.p4_frame.start_address() as u64)); } old_table }