Skip to content

Commit

Permalink
Merge pull request #579 from msft-jlange/ipi
Browse files Browse the repository at this point in the history
cpu: implement IPI support
  • Loading branch information
joergroedel authored Jan 13, 2025
2 parents d1c31ac + 2618d36 commit b8e9975
Show file tree
Hide file tree
Showing 19 changed files with 1,027 additions and 53 deletions.
1 change: 1 addition & 0 deletions bootlib/src/kernel_launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct KernelLaunchInfo {
pub vtom: u64,
pub debug_serial_port: u16,
pub use_alternate_injection: bool,
pub suppress_svsm_interrupts: bool,
pub platform_type: SvsmPlatformType,
}

Expand Down
6 changes: 3 additions & 3 deletions kernel/src/cpu/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const APIC_REGISTER_ICR: u64 = 0x830;
const APIC_REGISTER_SELF_IPI: u64 = 0x83F;

#[derive(Debug, PartialEq)]
enum IcrDestFmt {
pub enum IcrDestFmt {
Dest = 0,
OnlySelf = 1,
AllWithSelf = 2,
Expand All @@ -55,7 +55,7 @@ impl IcrDestFmt {
}

#[derive(Debug, PartialEq)]
enum IcrMessageType {
pub enum IcrMessageType {
Fixed = 0,
Unknown = 3,
Nmi = 4,
Expand All @@ -81,7 +81,7 @@ impl IcrMessageType {
}

#[bitfield(u64)]
struct ApicIcr {
pub struct ApicIcr {
pub vector: u8,
#[bits(3)]
pub message_type: IcrMessageType,
Expand Down
161 changes: 161 additions & 0 deletions kernel/src/cpu/cpuset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) Microsoft Corporation
//
// Author: Jon Lange ([email protected])

use core::sync::atomic::{AtomicU64, Ordering};

pub const MAX_CPUS: usize = 1024;

/// Represents a set of CPUs, based on CPU index. A maximum of `MAX_CPUS` can
/// be represented.
#[derive(Copy, Clone, Debug, Default)]
pub struct CpuSet {
bitmask: [u64; (MAX_CPUS + 63) / 64],
}

impl CpuSet {
pub fn new() -> Self {
Self::default()
}

/// Adds a CPU to the set.
///
/// * `cpu_index`: the index of the CPU to add to the set.
pub fn add(&mut self, cpu_index: usize) {
self.bitmask[cpu_index >> 6] |= 1u64 << (cpu_index & 0x3F);
}

/// Removes a CPU from the set.
///
/// * `cpu_index`: the index of the CPU to remove from the set.
pub fn remove(&mut self, cpu_index: usize) {
self.bitmask[cpu_index >> 6] &= !(1u64 << (cpu_index & 0x3F));
}

/// Produces an iterator to iterate over the set.
pub fn iter(&self) -> CpuSetIterator<'_> {
CpuSetIterator::new(self)
}
}

#[derive(Debug)]
pub struct CpuSetIterator<'a> {
cpu_set: &'a CpuSet,
current_mask: u64,
mask_index: usize,
}

impl<'a> CpuSetIterator<'a> {
fn new(cpu_set: &'a CpuSet) -> Self {
Self {
cpu_set,
current_mask: cpu_set.bitmask[0],
mask_index: 0,
}
}
}

impl Iterator for CpuSetIterator<'_> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.current_mask == 0 {
self.mask_index += 1;
if self.mask_index == self.cpu_set.bitmask.len() {
return None;
}

self.current_mask = self.cpu_set.bitmask[self.mask_index];
}

let index = self.current_mask.trailing_zeros();
self.current_mask &= !(1u64 << index);
Some((self.mask_index << 6) | index as usize)
}
}

/// Represents a set of CPUs, based on CPU index, which supports atomic
/// addition and removal. A maximum of 1024 CPUs can be represented.
#[derive(Debug, Default)]
pub struct AtomicCpuSet {
bitmask: [AtomicU64; (MAX_CPUS + 63) / 64],
}

impl AtomicCpuSet {
pub fn new() -> Self {
Self::default()
}

/// Adds a CPU to the set.
///
/// * `cpu_index`: the index of the CPU to add to the set.
/// * `ordering`: the atomic ordering rules to be used when adding the CPU.
pub fn add(&self, cpu_index: usize, ordering: Ordering) {
self.bitmask[cpu_index >> 6].fetch_or(1u64 << (cpu_index & 0x3F), ordering);
}

/// Removes a CPU from the set.
///
/// * `cpu_index`: the index of the CPU to remove from the set.
/// * `ordering`: the atomic ordering rules to be used when adding the CPU.
pub fn remove(&self, cpu_index: usize, ordering: Ordering) {
self.bitmask[cpu_index >> 6].fetch_and(!(1u64 << (cpu_index & 0x3F)), ordering);
}

/// Produces an iterator to iterate over the set. This iterator consumes
/// the set, so the action of iterating will remove all items from the set.
/// Items added while iteration is underway may or may not be observed by
/// the iterator.
///
/// * `ordering` - The memory ordering to apply as elements are removed
/// from the set.
pub fn iter(&self, ordering: Ordering) -> AtomicCpuSetIterator<'_> {
AtomicCpuSetIterator::new(self, ordering)
}
}

impl Clone for AtomicCpuSet {
fn clone(&self) -> Self {
let clone = AtomicCpuSet::new();
for (i, mask) in self.bitmask.iter().enumerate() {
clone.bitmask[i].store(mask.load(Ordering::Relaxed), Ordering::Relaxed);
}
clone
}
}

#[derive(Debug)]
pub struct AtomicCpuSetIterator<'a> {
cpu_set: &'a AtomicCpuSet,
ordering: Ordering,
mask_index: usize,
}

impl<'a> AtomicCpuSetIterator<'a> {
fn new(cpu_set: &'a AtomicCpuSet, ordering: Ordering) -> Self {
Self {
cpu_set,
ordering,
mask_index: 0,
}
}
}

impl Iterator for AtomicCpuSetIterator<'_> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.mask_index < self.cpu_set.bitmask.len() {
let mask = self.cpu_set.bitmask[self.mask_index].load(Ordering::Relaxed);
if mask != 0 {
let index = mask.trailing_zeros();
let cpu_mask = 1u64 << index;
self.cpu_set.bitmask[self.mask_index].fetch_and(!cpu_mask, self.ordering);
return Some((self.mask_index << 6) | index as usize);
}
self.mask_index += 1;
}

None
}
}
1 change: 1 addition & 0 deletions kernel/src/cpu/idt/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub const VC_VECTOR: usize = 29;
pub const SX_VECTOR: usize = 30;

pub const INT_INJ_VECTOR: usize = 0x50;
pub const IPI_VECTOR: usize = 0xE0;

bitflags::bitflags! {
/// Page fault error code flags.
Expand Down
3 changes: 3 additions & 0 deletions kernel/src/cpu/idt/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,7 @@ default_entry_no_ist name=int80 handler=system_call error_code=0 vector=0x80
// Interrupt injection vector
irq_entry name=int_inj vector=0x50

// IPI vector.
irq_entry name=ipi vector=0xE0

.popsection
19 changes: 13 additions & 6 deletions kernel/src/cpu/idt/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use super::super::tss::IST_DF;
use super::super::vc::handle_vc_exception;
use super::common::{
idt_mut, user_mode, IdtEntry, IdtEventType, PageFaultError, AC_VECTOR, BP_VECTOR, BR_VECTOR,
CP_VECTOR, DB_VECTOR, DE_VECTOR, DF_VECTOR, GP_VECTOR, HV_VECTOR, INT_INJ_VECTOR, MCE_VECTOR,
MF_VECTOR, NMI_VECTOR, NM_VECTOR, NP_VECTOR, OF_VECTOR, PF_VECTOR, SS_VECTOR, SX_VECTOR,
TS_VECTOR, UD_VECTOR, VC_VECTOR, XF_VECTOR,
CP_VECTOR, DB_VECTOR, DE_VECTOR, DF_VECTOR, GP_VECTOR, HV_VECTOR, INT_INJ_VECTOR, IPI_VECTOR,
MCE_VECTOR, MF_VECTOR, NMI_VECTOR, NM_VECTOR, NP_VECTOR, OF_VECTOR, PF_VECTOR, SS_VECTOR,
SX_VECTOR, TS_VECTOR, UD_VECTOR, VC_VECTOR, XF_VECTOR,
};
use crate::address::VirtAddr;
use crate::cpu::irq_state::{raw_get_tpr, raw_set_tpr, tpr_from_vector};
Expand Down Expand Up @@ -56,6 +56,7 @@ extern "C" {
fn asm_entry_sx();
fn asm_entry_int80();
fn asm_entry_irq_int_inj();
fn asm_entry_irq_ipi();

pub static mut HV_DOORBELL_ADDR: usize;
}
Expand Down Expand Up @@ -92,6 +93,7 @@ pub fn early_idt_init() {

// Interupts
idt.set_entry(0x80, IdtEntry::user_entry(asm_entry_int80));
idt.set_entry(IPI_VECTOR, IdtEntry::entry(asm_entry_irq_ipi));

// Load IDT
idt.load();
Expand Down Expand Up @@ -363,9 +365,14 @@ pub fn common_isr_handler(vector: usize) {
let cpu = this_cpu();
cpu.irqs_enable();

// Treat any unhandled interrupt as a spurious interrupt. Interrupt
// injection requests currently require no processing; they occur simply
// to ensure an exit from the guest.
// Process the requested interrupt vector.
match vector {
IPI_VECTOR => this_cpu().handle_ipi_interrupt(),
_ => {
// Ignore all unrecognized interrupt vectors and treat them as
// spurious interrupts.
}
}

// Disable interrupts before restoring TPR.
cpu.irqs_disable();
Expand Down
Loading

0 comments on commit b8e9975

Please sign in to comment.