Merge branch 'pti'

This commit is contained in:
Jeremy Soller
2018-01-19 20:06:59 -07:00
7 changed files with 195 additions and 100 deletions

View File

@@ -2,7 +2,6 @@ ENTRY(kstart)
OUTPUT_FORMAT(elf64-x86-64)
KERNEL_OFFSET = 0xffffff0000100000;
/* KERNEL_OFFSET = 0x100000; */
SECTIONS {
. = KERNEL_OFFSET;

View File

@@ -88,6 +88,18 @@ pub static mut TSS: TaskStateSegment = TaskStateSegment {
iomap_base: 0xFFFF
};
#[cfg(feature = "pti")]
pub unsafe fn set_tss_stack(stack: usize) {
use arch::x86_64::pti::{PTI_CPU_STACK, PTI_CONTEXT_STACK};
TSS.rsp[0] = (PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u64;
PTI_CONTEXT_STACK = stack;
}
#[cfg(not(feature = "pti"))]
pub unsafe fn set_tss_stack(stack: usize) {
TSS.rsp[0] = stack as u64;
}
/// Initialize GDT
pub unsafe fn init(tcb_offset: usize, stack_offset: usize) {
// Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing)
@@ -124,7 +136,7 @@ pub unsafe fn init(tcb_offset: usize, stack_offset: usize) {
GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
// Set the stack pointer when coming back from userspace
TSS.rsp[0] = stack_offset as u64;
set_tss_stack(stack_offset);
// Load the new GDT, which is correctly located in thread local storage
dtables::lgdt(&GDTR);

View File

@@ -4,64 +4,65 @@ use syscall;
#[naked]
pub unsafe extern fn syscall() {
#[inline(never)]
unsafe fn inner(stack: &mut SyscallStack) {
let mut a;
unsafe fn inner(stack: &mut SyscallStack) -> usize {
let rbp;
asm!("" : "={rax}"(a), "={rbp}"(rbp)
: : : "intel", "volatile");
asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");
// Map kernel
pti::map();
println!("{:X}, {:X}", stack.rax, stack.rbx);
a = syscall::syscall(a, stack.rbx, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack);
// Unmap kernel
pti::unmap();
asm!("" : : "{rax}"(a) : : "intel", "volatile");
syscall::syscall(stack.rax, stack.rbx, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack)
}
// Push scratch registers, minus rax for the return value
asm!("push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11
push rbx
push fs
mov r11, 0x18
mov fs, r11"
: : : : "intel", "volatile");
// Push scratch registers
asm!("push rax
push rbx
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11
push fs
mov r11, 0x18
mov fs, r11"
: : : : "intel", "volatile");
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
inner(&mut *(rsp as *mut SyscallStack));
// Map kernel
pti::map();
let a = inner(&mut *(rsp as *mut SyscallStack));
// Unmap kernel
pti::unmap();
asm!("" : : "{rax}"(a) : : "intel", "volatile");
// Interrupt return
asm!("pop fs
pop rbx
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
iretq"
: : : : "intel", "volatile");
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rbx
add rsp, 8
iretq"
: : : : "intel", "volatile");
}
#[allow(dead_code)]
#[repr(packed)]
pub struct SyscallStack {
pub fs: usize,
pub rbx: usize,
pub r11: usize,
pub r10: usize,
pub r9: usize,
@@ -70,6 +71,8 @@ pub struct SyscallStack {
pub rdi: usize,
pub rdx: usize,
pub rcx: usize,
pub rbx: usize,
pub rax: usize,
pub rip: usize,
pub cs: usize,
pub rflags: usize,

View File

@@ -166,22 +166,22 @@ macro_rules! interrupt {
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner() {
// Map kernel
$crate::arch::x86_64::pti::map();
$func
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
}
// 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!();
@@ -213,13 +213,7 @@ macro_rules! interrupt_stack {
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) {
// Map kernel
$crate::arch::x86_64::pti::map();
$func
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
}
// Push scratch registers
@@ -230,9 +224,15 @@ macro_rules! interrupt_stack {
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 $crate::arch::x86_64::macros::InterruptStack));
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
scratch_pop!();
@@ -266,13 +266,7 @@ macro_rules! interrupt_error {
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) {
// Map kernel
$crate::arch::x86_64::pti::map();
$func
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
}
// Push scratch registers
@@ -283,9 +277,15 @@ macro_rules! interrupt_error {
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
$crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStack));
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
// Pop scratch registers, error code, and return
fs_pop!();
scratch_pop!();
@@ -320,13 +320,7 @@ macro_rules! interrupt_stack_p {
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStackP) {
// Map kernel
$crate::arch::x86_64::pti::map();
$func
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
}
// Push scratch registers
@@ -338,9 +332,15 @@ macro_rules! interrupt_stack_p {
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 $crate::arch::x86_64::macros::InterruptStackP));
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
// Pop scratch registers and return
fs_pop!();
preserved_pop!();
@@ -377,13 +377,7 @@ macro_rules! interrupt_error_p {
pub unsafe extern fn $name () {
#[inline(never)]
unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStackP) {
// Map kernel
$crate::arch::x86_64::pti::map();
$func
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
}
// Push scratch registers
@@ -395,9 +389,15 @@ macro_rules! interrupt_error_p {
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Map kernel
$crate::arch::x86_64::pti::map();
// Call inner rust function
inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStackP));
// Unmap kernel
$crate::arch::x86_64::pti::unmap();
// Pop scratch registers, error code, and return
fs_pop!();
preserved_pop!();

View File

@@ -1,19 +1,76 @@
use core::ptr;
use memory::Frame;
use paging::ActivePageTable;
use paging::entry::EntryFlags;
#[cfg(feature = "pti")]
#[thread_local]
pub static mut PTI_CPU_STACK: [u8; 256] = [0; 256];
#[cfg(feature = "pti")]
#[thread_local]
pub static mut PTI_CONTEXT_STACK: usize = 0;
#[cfg(feature = "pti")]
#[inline(always)]
unsafe fn switch_stack(old: usize, new: usize) {
let old_rsp: usize;
asm!("" : "={rsp}"(old_rsp) : : : "intel", "volatile");
let offset_rsp = old - old_rsp;
let new_rsp = new - offset_rsp;
ptr::copy_nonoverlapping(
old_rsp as *const u8,
new_rsp as *mut u8,
offset_rsp
);
asm!("" : : "{rsp}"(new_rsp) : : "intel", "volatile");
}
#[cfg(feature = "pti")]
#[inline(always)]
pub unsafe fn map() {
let _cr3: usize;
asm!("mov $0, cr3
mov cr3, $0"
: "=r"(_cr3) : : "memory" : "intel", "volatile");
// {
// let mut active_table = unsafe { ActivePageTable::new() };
//
// // Map kernel heap
// let address = active_table.p4()[::KERNEL_HEAP_PML4].address();
// let frame = Frame::containing_address(address);
// let mut flags = active_table.p4()[::KERNEL_HEAP_PML4].flags();
// flags.remove(EntryFlags::PRESENT);
// active_table.p4_mut()[::KERNEL_HEAP_PML4].set(frame, flags);
//
// // Reload page tables
// active_table.flush_all();
// }
// Switch to per-context stack
switch_stack(PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(), PTI_CONTEXT_STACK);
}
#[cfg(feature = "pti")]
#[inline(always)]
pub unsafe fn unmap() {
let _cr3: usize;
asm!("mov $0, cr3
mov cr3, $0"
: "=r"(_cr3) : : "memory" : "intel", "volatile");
// Switch to per-CPU stack
switch_stack(PTI_CONTEXT_STACK, PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len());
// {
// let mut active_table = unsafe { ActivePageTable::new() };
//
// // Unmap kernel heap
// let address = active_table.p4()[::KERNEL_HEAP_PML4].address();
// let frame = Frame::containing_address(address);
// let mut flags = active_table.p4()[::KERNEL_HEAP_PML4].flags();
// flags.insert(EntryFlags::PRESENT);
// active_table.p4_mut()[::KERNEL_HEAP_PML4].set(frame, flags);
//
// // Reload page tables
// active_table.flush_all();
// }
}
#[cfg(not(feature = "pti"))]

View File

@@ -190,30 +190,54 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
::kmain_ap(cpu_id);
}
#[naked]
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
asm!("push r10
push r11
push r12
push r13
push r14
push r15"
: // No output
: "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
"{r11}"(sp), // Stack pointer
"{r12}"(1 << 9), // Flags - Set interrupt enable flag
"{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
"{r14}"(ip), // IP
"{r15}"(arg) // Argument
: // No clobbers
: "intel", "volatile");
// Unmap kernel
pti::unmap();
// Go to usermode
asm!("mov ds, r10d
mov es, r10d
mov fs, r11d
mov gs, r10d
push r10
push r12
push r13
push r14
push r15
iretq"
: // No output because it never returns
: "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
"{r11}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment
"{r12}"(sp), // Stack pointer
"{r13}"(1 << 9), // Flags - Set interrupt enable flag
"{r14}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
"{r15}"(ip) // IP
"{rdi}"(arg) // Argument
: // No clobers because it never returns
: "intel", "volatile");
asm!("mov ds, r14d
mov es, r14d
mov fs, r15d
mov gs, r14d
xor rax, rax
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
xor rsi, rsi
xor rdi, rdi
xor rbp, rbp
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
xor r12, r12
xor r13, r13
xor r14, r14
xor r15, r15
fninit
pop rdi
iretq"
: // No output because it never returns
: "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
"{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment
: // No clobbers because it never returns
: "intel", "volatile");
unreachable!();
}

View File

@@ -118,7 +118,7 @@ pub unsafe fn switch() -> bool {
(&mut *from_ptr).running = false;
(&mut *to_ptr).running = true;
if let Some(ref stack) = (*to_ptr).kstack {
gdt::TSS.rsp[0] = (stack.as_ptr() as usize + stack.len() - 256) as u64;
gdt::set_tss_stack(stack.as_ptr() as usize + stack.len());
}
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
}