[RFC v2 05/17] x86/apic: Add update_vector callback for Secure AVIC

Neeraj Upadhyay
2025-02-26T09:07:19Z

Add update_vector callback to set/clear ALLOWED_IRR field in
the APIC backing page. The ALLOWED_IRR field indicates the
interrupt vectors which the guest allows the hypervisor to
send (typically for emulated devices). Interrupt vectors used
exclusively by the guest itself (like IPI vectors) should not
be allowed to be injected into the guest for security reasons.
The update_vector callback is invoked from APIC vector domain
whenever a vector is allocated, freed or moved.

Co-developed-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
---
Changes since v1:

- No change.

arch/x86/include/asm/apic.h | 2 ++
arch/x86/kernel/apic/vector.c | 8 ++++++++
arch/x86/kernel/apic/x2apic_savic.c | 21 +++++++++++++++++++++
3 files changed, 31 insertions(+)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 3f70aa2f3aba..7970ead55f39 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -318,6 +318,8 @@ struct apic {
/* wakeup secondary CPU using 64-bit wakeup point */
int (*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip);

+ void (*update_vector)(unsigned int cpu, unsigned int vector, bool set);
+
char *name;
};

diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 72fa4bb78f0a..e0c9505e05f8 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -174,6 +174,8 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
apicd->prev_cpu = apicd->cpu;
WARN_ON_ONCE(apicd->cpu == newcpu);
} else {
+ if (apic->update_vector)
+ apic->update_vector(apicd->cpu, apicd->vector, false);
irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
managed);
}
@@ -183,6 +185,8 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
apicd->cpu = newcpu;
BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));
per_cpu(vector_irq, newcpu)[newvec] = desc;
+ if (apic->update_vector)
+ apic->update_vector(apicd->cpu, apicd->vector, true);
}

static void vector_assign_managed_shutdown(struct irq_data *irqd)
@@ -528,11 +532,15 @@ static bool vector_configure_legacy(unsigned int virq, struct irq_data *irqd,
if (irqd_is_activated(irqd)) {
trace_vector_setup(virq, true, 0);
apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
+ if (apic->update_vector)
+ apic->update_vector(apicd->cpu, apicd->vector, true);
} else {
/* Release the vector */
apicd->can_reserve = true;
irqd_set_can_reserve(irqd);
clear_irq_vector(irqd);
+ if (apic->update_vector)
+ apic->update_vector(apicd->cpu, apicd->vector, false);
realloc = true;
}
raw_spin_unlock_irqrestore(&vector_lock, flags);
diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c
index 505ef2d29311..d912c53dec7a 100644
--- a/arch/x86/kernel/apic/x2apic_savic.c
+++ b/arch/x86/kernel/apic/x2apic_savic.c
@@ -19,6 +19,9 @@

#include "local.h"

+#define VEC_POS(v) ((v) & (32 - 1))
+#define REG_POS(v) (((v) >> 5) << 4)
+
static DEFINE_PER_CPU(void *, apic_backing_page);

struct apic_id_node {
@@ -192,6 +195,22 @@ static void x2apic_savic_send_IPI_mask_allbutself(const struct cpumask *mask, in
__send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
}

+static void x2apic_savic_update_vector(unsigned int cpu, unsigned int vector, bool set)
+{
+ void *backing_page;
+ unsigned long *reg;
+ int reg_off;
+
+ backing_page = per_cpu(apic_backing_page, cpu);
+ reg_off = SAVIC_ALLOWED_IRR_OFFSET + REG_POS(vector);
+ reg = (unsigned long *)((char *)backing_page + reg_off);
+
+ if (set)
+ test_and_set_bit(VEC_POS(vector), reg);
+ else
+ test_and_clear_bit(VEC_POS(vector), reg);
+}
+
static void init_backing_page(void *backing_page)
{
struct apic_id_node *next_node, *this_cpu_node;
@@ -316,6 +335,8 @@ static struct apic apic_x2apic_savic __ro_after_init = {
.eoi = native_apic_msr_eoi,
.icr_read = native_x2apic_icr_read,
.icr_write = native_x2apic_icr_write,
+
+ .update_vector = x2apic_savic_update_vector,
};

apic_driver(apic_x2apic_savic);
--
2.34.1