155d01b11e
The MSR R/W scheme lets root request an arbitrary wrmsr/rdmsr on any CPU (used by cpufreqd/thermald). A bad MSR number or reserved-bit value raises #GP; on the raw wrmsr/rdmsr that is a kernel-mode fault that panics the whole machine at exit_this_context (unreachable!) — i.e. root userspace can crash the kernel. Observed on KVM: cpufreqd writing a legacy P-state MSR (#GP in the msr IPI handler) halted the boot right before the console/login. Add wrmsr_safe/rdmsr_safe (arch/x86_64): the faulting instruction sits in a __wrmsr_safe_start/end (resp. rdmsr) region, and the #GP handler recognises a fault inside those bounds and returns an error via recover_and_efault — the same fault-recovery mechanism already used for usercopy page faults. The MSR scheme (local path) and the cross-CPU msr IPI handler now use these and surface EIO to the caller (IPI failures propagated via a new MsrMailbox faulted flag) instead of panicking. 32-bit x86 keeps the raw path (untested).
67 lines
1.8 KiB
Rust
67 lines
1.8 KiB
Rust
use crate::{
|
|
arch::device::local_apic::the_local_apic, context, percpu::PercpuBlock, sync::CleanLockToken,
|
|
};
|
|
// Only the 32-bit x86 path uses the unguarded intrinsics; x86_64 goes through
|
|
// the #GP-recoverable wrmsr_safe/rdmsr_safe so a bad MSR cannot panic the kernel.
|
|
#[cfg(not(target_arch = "x86_64"))]
|
|
use x86::msr::{rdmsr, wrmsr};
|
|
|
|
interrupt!(wakeup, || {
|
|
unsafe { the_local_apic().eoi() };
|
|
});
|
|
|
|
interrupt!(tlb, || {
|
|
PercpuBlock::current().maybe_handle_tlb_shootdown();
|
|
|
|
unsafe { the_local_apic().eoi() };
|
|
});
|
|
|
|
interrupt!(switch, || {
|
|
unsafe { the_local_apic().eoi() };
|
|
|
|
let mut token = unsafe { CleanLockToken::new() };
|
|
let _ = context::switch(&mut token);
|
|
});
|
|
|
|
interrupt!(pit, || {
|
|
unsafe { the_local_apic().eoi() };
|
|
|
|
// Switch after a sufficient amount of time since the last switch.
|
|
let mut token = unsafe { CleanLockToken::new() };
|
|
context::switch::tick(&mut token);
|
|
});
|
|
|
|
interrupt!(msr, || {
|
|
let percpu = PercpuBlock::current();
|
|
let mailbox = percpu.msr_mailbox();
|
|
let op = mailbox.request();
|
|
|
|
let (result, faulted) = if op.is_write {
|
|
#[cfg(target_arch = "x86_64")]
|
|
{
|
|
let f = unsafe { crate::arch::wrmsr_safe(op.msr as u32, op.value) } != 0;
|
|
(op.value, f)
|
|
}
|
|
#[cfg(not(target_arch = "x86_64"))]
|
|
{
|
|
unsafe { wrmsr(op.msr as u32, op.value) };
|
|
(op.value, false)
|
|
}
|
|
} else {
|
|
#[cfg(target_arch = "x86_64")]
|
|
{
|
|
let mut v = 0u64;
|
|
let f = unsafe { crate::arch::rdmsr_safe(op.msr as u32, &mut v) } != 0;
|
|
(v, f)
|
|
}
|
|
#[cfg(not(target_arch = "x86_64"))]
|
|
{
|
|
(unsafe { rdmsr(op.msr as u32) }, false)
|
|
}
|
|
};
|
|
|
|
mailbox.finish_handle(result, faulted);
|
|
|
|
unsafe { the_local_apic().eoi() };
|
|
});
|