diff --git a/Cargo.lock b/Cargo.lock index 089b573..dd00ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,7 @@ dependencies = [ "kernel-common", "lock_api", "log", + "raw-cpuid", ] [[package]] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 300910b..9c97378 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -15,6 +15,7 @@ embedded-graphics = "0.8.1" kernel-common = {path = "../lib/kernel-common"} lock_api = "0.4.12" log = "0.4.22" +raw-cpuid = "11.2.0" [lints.clippy] missing_safety_doc = "allow" diff --git a/kernel/src/cpu/cpu.rs b/kernel/src/cpu/cpu.rs index 5cf4dbb..8b86eaf 100644 --- a/kernel/src/cpu/cpu.rs +++ b/kernel/src/cpu/cpu.rs @@ -1,6 +1,7 @@ -use core::arch::asm; +use core::arch::{asm, global_asm}; use kernel_common::instructions::sti; +use raw_cpuid::CpuId; use crate::{ cpu::{gdt::setup_gdt, idt::setup_idt}, @@ -10,6 +11,12 @@ use crate::{ }, }; +global_asm!(include_str!("syscall.s"), options(att_syntax)); + +extern "C" { + fn syscall(); +} + #[no_mangle] extern "C" fn ap_main() -> ! { setup_gdt(); @@ -25,9 +32,24 @@ extern "C" fn ap_main() -> ! { panic!("Yielding to idle task failed"); } pub fn set_cpu_flags() { + let cpuid = CpuId::new(); + let features = cpuid.get_feature_info().unwrap(); + let extended_features = cpuid.get_extended_feature_info().unwrap(); unsafe { - // SMAP and SMEP - asm!("mov rax, cr4; bts rax, 20; bts rax, 21; mov cr4, rax", out("rax") _); + // Time Stamp Disable, SMEP and SMAP + asm!("mov rax, cr4; bts rax, 2; bts rax, 20; bts rax, 21; mov cr4, rax", out("rax") _); + if features.has_mce() { + asm!("mov rax, cr4; bts rax, 6; mov cr4, rax", out("rax") _); + } + if extended_features.has_umip() { + asm!("mov rax, cr4; bts rax, 11; mov cr4, rax", out("rax") _); + } + // System Call Extensions + asm!("rdmsr; bts rax, 0; wrmsr", in("rcx") 0xc0000080_u64, out("rax") _, out("rdx") _); + asm!("wrmsr", in("rcx") 0xc0000081_u64, in("rax") 0, in("rdx") 8 | 16 << 16); + asm!("wrmsr", in("rcx") 0xc0000082_u64, in("rax") syscall, in("rdx") syscall as u64 >> 32); + // Clear IF and DF + asm!("wrmsr", in("rcx") 0xc0000084_u64, in("rax") 1 << 9 | 1 << 10, in("rdx") 0); } } pub fn enable_user_memory_access() { diff --git a/kernel/src/cpu/gdt.rs b/kernel/src/cpu/gdt.rs index 6dae714..8d86f73 100644 --- a/kernel/src/cpu/gdt.rs +++ b/kernel/src/cpu/gdt.rs @@ -58,6 +58,7 @@ pub fn setup_gdt() { tss.rsp[0] = allocate_stack(); tss.ist[0] = allocate_stack(); tss.ist[1] = allocate_stack(); + tss.ist[2] = allocate_stack(); let gdt = Box::leak(Box::new(GDT { entries: [ GDTEntry { @@ -88,16 +89,16 @@ pub fn setup_gdt() { limit_low: 0, base_low: 0, base_middle: 0, - access: 0xfa, - flags: 0x20, + access: 0xf2, + flags: 0, base_high: 0, }, GDTEntry { limit_low: 0, base_low: 0, base_middle: 0, - access: 0xf2, - flags: 0, + access: 0xfa, + flags: 0x20, base_high: 0, }, ], diff --git a/kernel/src/cpu/idt.rs b/kernel/src/cpu/idt.rs index 6185dc7..91c1a30 100644 --- a/kernel/src/cpu/idt.rs +++ b/kernel/src/cpu/idt.rs @@ -325,4 +325,5 @@ pub fn setup_idt() { } idt.entries[2].ist = 1; // NMI idt.entries[8].ist = 2; // Double fault + idt.entries[18].ist = 3; // Machine Check } diff --git a/kernel/src/cpu/isr.rs b/kernel/src/cpu/isr.rs index e7523f0..0137d96 100644 --- a/kernel/src/cpu/isr.rs +++ b/kernel/src/cpu/isr.rs @@ -111,7 +111,7 @@ extern "C" fn isr_handler(state: &mut ISRState) { let lapic_id = get_current_lapic_id(); IN_ISR_HANDLER[lapic_id].store(true, Ordering::SeqCst); if state.isr < 32 { - if state.cs == 0x1b && state.isr != 2 && state.isr != 8 { + if state.cs == 0x23 && state.isr != 2 && state.isr != 8 && state.isr != 18 { warn!("Exception in usermode: {}", EXCEPTIONS[state.isr as usize]); terminate_current_task(); state.isr = ISR_SCHEDULER; diff --git a/kernel/src/cpu/syscall.s b/kernel/src/cpu/syscall.s new file mode 100644 index 0000000..d8f7e48 --- /dev/null +++ b/kernel/src/cpu/syscall.s @@ -0,0 +1,5 @@ +.text + +.global syscall +syscall: + jmp . diff --git a/kernel/src/cpu/usermode.s b/kernel/src/cpu/usermode.s index 1ae631e..5bd79a6 100644 --- a/kernel/src/cpu/usermode.s +++ b/kernel/src/cpu/usermode.s @@ -2,15 +2,15 @@ .global jump_usermode jump_usermode: - mov $0x23, %ax + mov $0x1b, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs - push $0x23 + push $0x1b push $0 pushf - push $0x1b + push $0x23 push %rdi xor %rax, %rax diff --git a/loader/src/main.rs b/loader/src/main.rs index 4417ea1..bd88d9a 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -54,6 +54,7 @@ fn main() -> Status { uefi::helpers::init().unwrap(); BOOT_SERVICES_ACTIVE.store(true, Ordering::SeqCst); assert!(features.has_rdrand()); + assert!(features.has_tsc()); let extended_features = cpuid.get_extended_feature_info().unwrap(); assert!(extended_features.has_smap()); assert!(extended_features.has_smep()); diff --git a/qemu.sh b/qemu.sh index 71378ce..1bd9d83 100755 --- a/qemu.sh +++ b/qemu.sh @@ -2,4 +2,4 @@ # shellcheck disable=SC2068 set -euo pipefail ./build.sh -qemu-system-x86_64 -M q35 -accel kvm -cpu qemu64,rdrand,smap,smep -smp 4 -m 256M -L /usr/share/OVMF -bios OVMF_CODE.fd -drive file=img/os.img,format=raw $@ +qemu-system-x86_64 -M q35 -accel kvm -cpu qemu64,rdrand,smap,smep,umip -smp 4 -m 256M -L /usr/share/OVMF -bios OVMF_CODE.fd -drive file=img/os.img,format=raw $@