Merge branch 'pti'
This commit is contained in:
@@ -2,7 +2,6 @@ ENTRY(kstart)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
KERNEL_OFFSET = 0xffffff0000100000;
|
||||
/* KERNEL_OFFSET = 0x100000; */
|
||||
|
||||
SECTIONS {
|
||||
. = KERNEL_OFFSET;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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!();
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user