Nothing to see here, move along
at main 197 lines 5.2 kB view raw
1use core::arch::global_asm; 2 3use lancer_core::object_layout::SchedContextObject; 4use x86_64::structures::paging::PhysFrame; 5 6use crate::arch::syscall as arch_syscall; 7use crate::proc::context::CpuContext; 8use crate::proc::{ProcessManager, ProcessState}; 9use crate::sync::SyncUnsafe; 10use crate::types::{MAX_CPUS, Pid}; 11use crate::wcet::region::WcetTracker; 12 13const IA32_FS_BASE: u32 = 0xC000_0100; 14 15#[inline] 16pub(crate) fn read_fs_base() -> u64 { 17 unsafe { 18 let lo: u32; 19 let hi: u32; 20 core::arch::asm!( 21 "rdmsr", 22 in("ecx") IA32_FS_BASE, 23 out("eax") lo, 24 out("edx") hi, 25 options(nomem, nostack, preserves_flags), 26 ); 27 ((hi as u64) << 32) | (lo as u64) 28 } 29} 30 31#[inline] 32pub(crate) fn write_fs_base(val: u64) { 33 unsafe { 34 core::arch::asm!( 35 "wrmsr", 36 in("ecx") IA32_FS_BASE, 37 in("eax") val as u32, 38 in("edx") (val >> 32) as u32, 39 options(nomem, nostack, preserves_flags), 40 ); 41 } 42} 43 44unsafe extern "C" { 45 fn restore_context_and_iretq(ctx: *const CpuContext); 46} 47 48static SWITCH_WCET: [SyncUnsafe<WcetTracker<16>>; MAX_CPUS] = 49 [const { SyncUnsafe::new(WcetTracker::new("context_switch")) }; MAX_CPUS]; 50 51#[allow(dead_code)] 52pub fn log_switch_wcet() { 53 let idx = arch_syscall::cpu_index(); 54 unsafe { SWITCH_WCET[idx].as_ref_unchecked() }.log_summary(); 55} 56 57pub fn enter_context(ctx: &CpuContext) -> ! { 58 unsafe { restore_context_and_iretq(ctx as *const CpuContext) }; 59 unreachable!() 60} 61 62pub fn switch_to( 63 ptable: &mut ProcessManager, 64 from_pid: Pid, 65 to_pid: Pid, 66 frame: &mut CpuContext, 67) -> bool { 68 if from_pid == to_pid { 69 return false; 70 } 71 72 let idx = arch_syscall::cpu_index(); 73 let tracker = unsafe { SWITCH_WCET[idx].as_mut_unchecked() }; 74 let _guard = crate::wcet::region::WcetGuard::new(tracker); 75 76 let (from_was_running, old_pml4, new_pml4, sc_ctx, fs_base) = { 77 let Some(((from_sched, from_exec), (to_sched, to_exec))) = 78 ptable.pair_mut(from_pid, to_pid) 79 else { 80 return false; 81 }; 82 83 from_exec.fs_base = read_fs_base(); 84 from_exec.saved_context = *frame; 85 from_exec.seal_context(); 86 87 from_sched.run_cpu = None; 88 89 let from_was_running = from_sched.state() == ProcessState::Running; 90 if from_was_running && from_sched.transition_to(ProcessState::Ready).is_err() { 91 crate::kprintln!( 92 "[sched] BUG: pid {} failed Running -> Ready", 93 from_pid.raw() 94 ); 95 } 96 97 let old_pml4 = from_exec.pml4_phys.raw(); 98 99 if to_sched.transition_to(ProcessState::Running).is_err() { 100 crate::kprintln!( 101 "[sched] BUG: pid {} failed -> Running (state={:?}), skipping switch", 102 to_pid.raw(), 103 to_sched.state() 104 ); 105 if from_was_running { 106 let r = from_sched.transition_to(ProcessState::Running); 107 debug_assert!(r.is_ok()); 108 } 109 return false; 110 } 111 112 let new_pml4 = to_exec.pml4_phys.raw(); 113 114 to_exec.verify_context(to_pid); 115 *frame = to_exec.saved_context; 116 frame.validate_user(to_pid.raw()); 117 118 arch_syscall::set_fpu_state_ptr(to_exec.fpu_state.data.as_mut_ptr()); 119 120 to_sched.run_cpu = Some(idx as u16); 121 122 let sc_ctx = to_sched.sched_context(); 123 let fs_base = to_exec.fs_base; 124 125 (from_was_running, old_pml4, new_pml4, sc_ctx, fs_base) 126 }; 127 128 if from_was_running { 129 ptable.enqueue_ready(from_pid); 130 } 131 132 if let Some((sc_id, sc_gen)) = sc_ctx { 133 let now_us = crate::wcet::tsc::cycles_to_ns(crate::wcet::tsc::read_tsc()) / 1000; 134 let mut pool = crate::cap::pool::POOL.lock(); 135 if let Ok(sc) = pool.write_as::<SchedContextObject>(sc_id, sc_gen) { 136 super::context::mark_dispatched(sc, now_us); 137 } 138 } 139 140 write_fs_base(fs_base); 141 142 arch_syscall::set_current_process(to_pid); 143 super::set_current(to_pid); 144 145 if old_pml4 != new_pml4 { 146 unsafe { 147 x86_64::registers::control::Cr3::write( 148 PhysFrame::containing_address(new_pml4), 149 x86_64::registers::control::Cr3Flags::empty(), 150 ); 151 } 152 } 153 154 true 155} 156 157global_asm!( 158 r#" 159.global restore_context_and_iretq 160.type restore_context_and_iretq, @function 161restore_context_and_iretq: 162 cli 163 164 push qword ptr [rdi + 152] 165 push qword ptr [rdi + 128] 166 push qword ptr [rdi + 136] 167 push qword ptr [rdi + 144] 168 push qword ptr [rdi + 120] 169 170 mov rax, [rdi + 0] 171 mov rbx, [rdi + 8] 172 mov rcx, [rdi + 16] 173 mov rdx, [rdi + 24] 174 mov rsi, [rdi + 32] 175 mov rbp, [rdi + 48] 176 mov r8, [rdi + 56] 177 mov r9, [rdi + 64] 178 mov r10, [rdi + 72] 179 mov r11, [rdi + 80] 180 mov r12, [rdi + 88] 181 mov r13, [rdi + 96] 182 mov r14, [rdi + 104] 183 mov r15, [rdi + 112] 184 mov rdi, [rdi + 40] 185 186 push rax 187 mov rax, [rsp + 16] 188 test rax, 3 189 pop rax 190 jz .restore_no_swap 191 swapgs 192.restore_no_swap: 193 iretq 194 195.size restore_context_and_iretq, . - restore_context_and_iretq 196"# 197);