Files
RedBear-OS/src/arch/x86_shared/interrupt/ipi.rs
T
vasilito 155d01b11e kernel(x86_64): make /scheme/sys/msr MSR access #GP-safe
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).
2026-07-16 12:11:34 +09:00

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() };
});