Skip to content

Commit

Permalink
platform: enable interrupts when possible
Browse files Browse the repository at this point in the history
Enable the use of interrupts whenever the kernel is executing outside of
an IRQ guard.  This is not safe on SNP systems that do not use
Restricted Injection but is safe in all other configurations.

Signed-off-by: Jon Lange <[email protected]>
  • Loading branch information
msft-jlange committed Oct 23, 2024
1 parent 4a53ac2 commit 0f8cacb
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 3 deletions.
13 changes: 13 additions & 0 deletions kernel/src/cpu/irq_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ impl IrqState {
pub fn count(&self) -> isize {
self.count.load(Ordering::Relaxed)
}

/// Changes whether interrupts will be enabled when the nesting count
/// drops to zero.
///
/// # Safety
///
/// The caller must ensure that the current nesting count is non-zero,
/// and must ensure that the specified value is appropriate for the
/// current environment.
pub unsafe fn set_restore_state(&self, enabled: bool) {
assert!(self.count.load(Ordering::Relaxed) != 0);
self.state.store(enabled, Ordering::Relaxed);
}
}

impl Drop for IrqState {
Expand Down
11 changes: 11 additions & 0 deletions kernel/src/cpu/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,17 @@ impl PerCpu {
}

pub fn schedule_init(&self) -> TaskPointer {
// If the platform permits the use of interrupts, then ensure that
// interrupts will be enabled on the current CPU when leaving the
// scheduler environment. This is done after disabling interrupts
// for scheduler initialization so that the first interrupt that can
// be received will always observe that there is a current task and
// not the boot thread.
if SVSM_PLATFORM.as_dyn_ref().use_interrupts() {
unsafe {
self.irq_state.set_restore_state(true);
}
}
let task = self.runqueue.lock_write().schedule_init();
self.current_stack.set(task.stack_bounds());
task
Expand Down
3 changes: 3 additions & 0 deletions kernel/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ pub trait SvsmPlatform {
/// Queries the state of APIC registration on this system.
fn query_apic_registration_state(&self) -> bool;

/// Determines whether the platform supports interrupts to the SVSM.
fn use_interrupts(&self) -> bool;

/// Signal an IRQ on one or more CPUs.
fn post_irq(&self, icr: u64) -> Result<(), SvsmError>;

Expand Down
4 changes: 4 additions & 0 deletions kernel/src/platform/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ impl SvsmPlatform for NativePlatform {
false
}

fn use_interrupts(&self) -> bool {
true
}

fn post_irq(&self, icr: u64) -> Result<(), SvsmError> {
write_msr(APIC_MSR_ICR, icr);
Ok(())
Expand Down
22 changes: 19 additions & 3 deletions kernel/src/platform/snp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::sev::hv_doorbell::current_hv_doorbell;
use crate::sev::msr_protocol::{
hypervisor_ghcb_features, request_termination_msr, verify_ghcb_version, GHCBHvFeatures,
};
use crate::sev::status::vtom_enabled;
use crate::sev::status::{sev_restricted_injection, vtom_enabled};
use crate::sev::{
init_hypervisor_ghcb_features, pvalidate_range, sev_status_init, sev_status_verify, PvalidateOp,
};
Expand Down Expand Up @@ -69,11 +69,15 @@ impl From<PageValidateOp> for PvalidateOp {
}

#[derive(Clone, Copy, Debug)]
pub struct SnpPlatform {}
pub struct SnpPlatform {
can_use_interrupts: bool,
}

impl SnpPlatform {
pub fn new() -> Self {
Self {}
Self {
can_use_interrupts: false,
}
}
}

Expand All @@ -87,6 +91,14 @@ impl SvsmPlatform for SnpPlatform {
fn env_setup(&mut self, _debug_serial_port: u16, vtom: usize) -> Result<(), SvsmError> {
sev_status_init();
VTOM.init(&vtom).map_err(|_| SvsmError::PlatformInit)?;

// Now that SEV status is initialized, determine whether this platform
// supports the use of SVSM interrupts. SVSM interrupts are supported
// if this system uses restricted injection.
if sev_restricted_injection() {
self.can_use_interrupts = true;
}

Ok(())
}

Expand Down Expand Up @@ -255,6 +267,10 @@ impl SvsmPlatform for SnpPlatform {
APIC_EMULATION_REG_COUNT.load(Ordering::Relaxed) > 0
}

fn use_interrupts(&self) -> bool {
self.can_use_interrupts
}

fn post_irq(&self, icr: u64) -> Result<(), SvsmError> {
current_ghcb().hv_ipi(icr)?;
Ok(())
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/platform/tdp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ impl SvsmPlatform for TdpPlatform {
false
}

fn use_interrupts(&self) -> bool {
true
}

fn post_irq(&self, _icr: u64) -> Result<(), SvsmError> {
Err(SvsmError::Tdx)
}
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/sev/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ pub fn vtom_enabled() -> bool {
sev_flags().contains(SEVStatusFlags::VTOM)
}

pub fn sev_restricted_injection() -> bool {
sev_flags().contains(SEVStatusFlags::REST_INJ)
}

pub fn sev_status_verify() {
let required = SEVStatusFlags::SEV | SEVStatusFlags::SEV_ES | SEVStatusFlags::SEV_SNP;
let supported = SEVStatusFlags::DBGSWP
Expand Down

0 comments on commit 0f8cacb

Please sign in to comment.