kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Cc: linux-kernel@vger.kernel.org, bp@alien8.de, tglx@linutronix.de,
	 mingo@redhat.com, dave.hansen@linux.intel.com,
	Thomas.Lendacky@amd.com,  nikunj@amd.com, Santosh.Shukla@amd.com,
	Vasant.Hegde@amd.com,  Suravee.Suthikulpanit@amd.com,
	David.Kaplan@amd.com, x86@kernel.org,  hpa@zytor.com,
	peterz@infradead.org, pbonzini@redhat.com, kvm@vger.kernel.org,
	 kirill.shutemov@linux.intel.com, huibo.wang@amd.com,
	naveen.rao@amd.com,  kai.huang@intel.com
Subject: Re: [RFC PATCH v8 15/35] x86/apic: Unionize apic regs for 32bit/64bit access w/o type casting
Date: Wed, 9 Jul 2025 07:32:53 -0700	[thread overview]
Message-ID: <aG59lcEc3ZBq8aHZ@google.com> (raw)
In-Reply-To: <20250709033242.267892-16-Neeraj.Upadhyay@amd.com>

On Wed, Jul 09, 2025, Neeraj Upadhyay wrote:
> Define apic_page construct to unionize APIC register 32bit/64bit
> accesses and use it in apic_{get|set}*() to avoid using type
> casting.
> 
> As Secure AVIC APIC driver requires accessing APIC page at byte

No, it does not.  Literally all two callers of get_reg_bitmap(), the only user
of ->bytes, immediately cast the return to a "void *".

And you most definitely don't need a common, unionized struct to be able to reference
a byte offset, just define a "struct secure_apic_page".

> offsets (to get an APIC register's bitmap start address), support
> byte access granularity in apic_page (in addition to 32-bit and
> 64-bit accesses).
> 
> One caveat of this change is that the generated code is slighly
> larger. Below is the code generation for apic_get_reg() using
> gcc-14.2:
> 
> - Without change:
> 
> apic_get_reg:
> 
> 89 f6       mov    %esi,%esi
> 8b 04 37    mov    (%rdi,%rsi,1),%eax
> c3          ret
> 
> - With change:
> 
> apic_get_reg:
> 
> c1 ee 02    shr    $0x2,%esi
> 8b 04 b7    mov    (%rdi,%rsi,4),%eax
> c3          ret
> 
> lapic.o text size change is shown below:
> 
> Obj        Old-size      New-size
> 
> lapic.o    28800         28832
> 
> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
> ---
> Changes since v7:
>  - Commit log update.
> 
>  arch/x86/include/asm/apic.h | 25 +++++++++++++++++++++----
>  1 file changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
> index 07ba4935e873..b7cbe9ba363e 100644
> --- a/arch/x86/include/asm/apic.h
> +++ b/arch/x86/include/asm/apic.h
> @@ -525,26 +525,43 @@ static inline int apic_find_highest_vector(void *bitmap)
>  	return -1;
>  }
>  
> +struct apic_page {
> +	union {
> +		u64     regs64[PAGE_SIZE / 8];
> +		u32     regs[PAGE_SIZE / 4];
> +		u8      bytes[PAGE_SIZE];
> +	};
> +} __aligned(PAGE_SIZE);
> +
>  static inline u32 apic_get_reg(void *regs, int reg)
>  {
> -	return *((u32 *) (regs + reg));
> +	struct apic_page *ap = regs;
> +
> +	return ap->regs[reg / 4];
>  }

NAK.

I really, *really* don't like this patch.  IMO, the casting code is more "obvious"
and thus easier to follow.  And there is still casting going on, i.e. to a
"struct apic_page".

_If_ we want to go this route, then all of the open coded literals need to be
replaced with sizeof().  But I'd still very strongly prefer we not do this in
the first place.

Jumping ahead a bit, I also recommend the secure AVIC stuff name its global
varaible "secure_apic_page", because just "apic_page" could result in avoidable
collisions.

There are also a number of extraneous local variables in x2apic_savic.c, some of
which are actively dangerous.  E.g. using a local "bitmap" in savic_eoi() makes
it possible to reuse a pointer and access the wrong bitmap.

E.g.

---
 arch/x86/include/asm/apic.h         | 40 ++++--------------
 arch/x86/kernel/apic/x2apic_savic.c | 65 +++++++++++------------------
 2 files changed, 32 insertions(+), 73 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index e8a32a3eea86..a26e66d66444 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -536,67 +536,41 @@ static inline int apic_find_highest_vector(void *bitmap)
 	return -1;
 }
 
-struct apic_page {
-	union {
-		u64     regs64[PAGE_SIZE / 8];
-		u32     regs[PAGE_SIZE / 4];
-		u8      bytes[PAGE_SIZE];
-	};
-} __aligned(PAGE_SIZE);
-
 static inline u32 apic_get_reg(void *regs, int reg)
 {
-	struct apic_page *ap = regs;
-
-	return ap->regs[reg / 4];
+	return *((u32 *) (regs + reg));
 }
 
 static inline void apic_set_reg(void *regs, int reg, u32 val)
 {
-	struct apic_page *ap = regs;
-
-	ap->regs[reg / 4] = val;
+	*((u32 *) (regs + reg)) = val;
 }
 
 static __always_inline u64 apic_get_reg64(void *regs, int reg)
 {
-	struct apic_page *ap = regs;
-
 	BUILD_BUG_ON(reg != APIC_ICR);
-
-	return ap->regs64[reg / 8];
+	return *((u64 *) (regs + reg));
 }
 
 static __always_inline void apic_set_reg64(void *regs, int reg, u64 val)
 {
-	struct apic_page *ap = regs;
-
 	BUILD_BUG_ON(reg != APIC_ICR);
-	ap->regs64[reg / 8] = val;
-}
-
-static inline unsigned int get_vec_bit(unsigned int vec)
-{
-	/*
-	 * The registers are 32-bit wide and 16-byte aligned.
-	 * Compensate for the resulting bit number spacing.
-	 */
-	return vec + 96 * (vec / 32);
+	*((u64 *) (regs + reg)) = val;
 }
 
 static inline void apic_clear_vector(int vec, void *bitmap)
 {
-	clear_bit(get_vec_bit(vec), bitmap);
+	clear_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
 }
 
 static inline void apic_set_vector(int vec, void *bitmap)
 {
-	set_bit(get_vec_bit(vec), bitmap);
+	set_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
 }
 
 static inline int apic_test_vector(int vec, void *bitmap)
 {
-	return test_bit(get_vec_bit(vec), bitmap);
+	return test_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
 }
 
 /*
diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c
index 2849f2354bf9..99d5f6104bc2 100644
--- a/arch/x86/kernel/apic/x2apic_savic.c
+++ b/arch/x86/kernel/apic/x2apic_savic.c
@@ -17,7 +17,11 @@
 
 #include "local.h"
 
-static struct apic_page __percpu *apic_page __ro_after_init;
+struct secure_apic_page {
+	u8 *regs[PAGE_SIZE];
+} __aligned(PAGE_SIZE);
+
+static struct secure_apic_page __percpu *secure_apic_page __ro_after_init;
 
 static inline void savic_wr_control_msr(u64 val)
 {
@@ -31,9 +35,7 @@ static int savic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 
 static inline void *get_reg_bitmap(unsigned int cpu, unsigned int offset)
 {
-	struct apic_page *ap = per_cpu_ptr(apic_page, cpu);
-
-	return &ap->bytes[offset];
+	return &per_cpu_ptr(secure_apic_page, cpu)->regs[offset];
 }
 
 static inline void update_vector(unsigned int cpu, unsigned int offset,
@@ -51,7 +53,7 @@ static inline void update_vector(unsigned int cpu, unsigned int offset,
 
 static u32 savic_read(u32 reg)
 {
-	struct apic_page *ap = this_cpu_ptr(apic_page);
+	void *ap = this_cpu_ptr(secure_apic_page);
 
 	/*
 	 * When Secure AVIC is enabled, rdmsr/wrmsr of APIC registers
@@ -129,14 +131,10 @@ static inline void self_ipi_reg_write(unsigned int vector)
 
 static void send_ipi_dest(unsigned int cpu, unsigned int vector, bool nmi)
 {
-	if (nmi) {
-		struct apic_page *ap = per_cpu_ptr(apic_page, cpu);
-
-		apic_set_reg(ap, SAVIC_NMI_REQ, 1);
-		return;
-	}
-
-	update_vector(cpu, APIC_IRR, vector, true);
+	if (nmi)
+		apic_set_reg(per_cpu_ptr(secure_apic_page, cpu), SAVIC_NMI_REQ, 1);
+	else
+		update_vector(cpu, APIC_IRR, vector, true);
 }
 
 static void send_ipi_allbut(unsigned int vector, bool nmi)
@@ -166,7 +164,6 @@ static inline void self_ipi(unsigned int vector, bool nmi)
 
 static void savic_icr_write(u32 icr_low, u32 icr_high)
 {
-	struct apic_page *ap = this_cpu_ptr(apic_page);
 	unsigned int dsh, vector;
 	u64 icr_data;
 	bool nmi;
@@ -193,12 +190,12 @@ static void savic_icr_write(u32 icr_low, u32 icr_high)
 	icr_data = ((u64)icr_high) << 32 | icr_low;
 	if (dsh != APIC_DEST_SELF)
 		savic_ghcb_msr_write(APIC_ICR, icr_data);
-	apic_set_reg64(ap, APIC_ICR, icr_data);
+	apic_set_reg64(this_cpu_ptr(secure_apic_page), APIC_ICR, icr_data);
 }
 
 static void savic_write(u32 reg, u32 data)
 {
-	struct apic_page *ap = this_cpu_ptr(apic_page);
+	struct secure_apic_page *ap = this_cpu_ptr(secure_apic_page);
 
 	switch (reg) {
 	case APIC_LVTT:
@@ -303,19 +300,15 @@ static void savic_update_vector(unsigned int cpu, unsigned int vector, bool set)
 static void savic_eoi(void)
 {
 	unsigned int cpu;
-	void *bitmap;
 	int vec;
 
 	cpu = raw_smp_processor_id();
-	bitmap = get_reg_bitmap(cpu, APIC_ISR);
-	vec = apic_find_highest_vector(bitmap);
+	vec = apic_find_highest_vector(get_reg_bitmap(cpu, APIC_ISR));
 	if (WARN_ONCE(vec == -1, "EOI write while no active interrupt in APIC_ISR"))
 		return;
 
-	bitmap = get_reg_bitmap(cpu, APIC_TMR);
-
 	/* Is level-triggered interrupt? */
-	if (apic_test_vector(vec, bitmap)) {
+	if (apic_test_vector(vec, get_reg_bitmap(cpu, APIC_TMR))) {
 		update_vector(cpu, APIC_ISR, vec, false);
 		/*
 		 * Propagate the EOI write to hv for level-triggered interrupts.
@@ -333,18 +326,6 @@ static void savic_eoi(void)
 	}
 }
 
-static void init_apic_page(struct apic_page *ap)
-{
-	u32 apic_id;
-
-	/*
-	 * Before Secure AVIC is enabled, APIC msr reads are intercepted.
-	 * APIC_ID msr read returns the value from the Hypervisor.
-	 */
-	apic_id = native_apic_msr_read(APIC_ID);
-	apic_set_reg(ap, APIC_ID, apic_id);
-}
-
 static void savic_teardown(void)
 {
 	/* Disable Secure AVIC */
@@ -354,13 +335,17 @@ static void savic_teardown(void)
 
 static void savic_setup(void)
 {
-	void *backing_page;
+	struct secure_apic_page *ap = this_cpu_ptr(secure_apic_page);
 	enum es_result res;
 	unsigned long gpa;
 
-	backing_page = this_cpu_ptr(apic_page);
-	init_apic_page(backing_page);
-	gpa = __pa(backing_page);
+	/*
+	 * Before Secure AVIC is enabled, APIC msr reads are intercepted.
+	 * APIC_ID msr read returns the value from the Hypervisor.
+	 */
+	apic_set_reg(ap, APIC_ID, native_apic_msr_read(APIC_ID));
+
+	gpa = __pa(ap);
 
 	/*
 	 * The NPT entry for a vCPU's APIC backing page must always be
@@ -389,8 +374,8 @@ static int savic_probe(void)
 		/* unreachable */
 	}
 
-	apic_page = alloc_percpu(struct apic_page);
-	if (!apic_page)
+	secure_apic_page = alloc_percpu(struct secure_apic_page);
+	if (!secure_apic_page)
 		snp_abort();
 
 	return 1;

base-commit: 620bd94fb00da8482556057cea765656b8263b71
--

  reply	other threads:[~2025-07-09 14:32 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-09  3:32 [RFC PATCH v8 00/35] AMD: Add Secure AVIC Guest Support Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 01/35] KVM: x86: Open code setting/clearing of bits in the ISR Neeraj Upadhyay
2025-07-09 14:03   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 02/35] KVM: x86: Remove redundant parentheses around 'bitmap' Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 03/35] x86/apic: KVM: Deduplicate APIC vector => register+bit math Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 04/35] KVM: x86: Rename VEC_POS/REG_POS macro usages Neeraj Upadhyay
2025-07-09 14:05   ` Sean Christopherson
2025-07-09 14:09   ` Sean Christopherson
2025-07-10  3:37     ` Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 05/35] KVM: x86: Change lapic regs base address to void pointer Neeraj Upadhyay
2025-07-09 14:05   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 06/35] KVM: x86: Rename find_highest_vector() Neeraj Upadhyay
2025-07-09 14:05   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 07/35] KVM: x86: Rename lapic get/set_reg() helpers Neeraj Upadhyay
2025-07-09 14:06   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 08/35] KVM: x86: Rename lapic get/set_reg64() helpers Neeraj Upadhyay
2025-07-09 14:06   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 09/35] KVM: x86: Rename lapic set/clear vector helpers Neeraj Upadhyay
2025-07-09 14:06   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 10/35] x86/apic: KVM: Move apic_find_highest_vector() to a common header Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 11/35] x86/apic: KVM: Move lapic get/set helpers to common code Neeraj Upadhyay
2025-07-09 14:06   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 12/35] x86/apic: KVM: Move lapic set/clear_vector() " Neeraj Upadhyay
2025-07-09 14:07   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 13/35] x86/apic: KVM: Move apic_test)vector() " Neeraj Upadhyay
2025-07-09 14:07   ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 14/35] x86/apic: Rename 'reg_off' to 'reg' Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 15/35] x86/apic: Unionize apic regs for 32bit/64bit access w/o type casting Neeraj Upadhyay
2025-07-09 14:32   ` Sean Christopherson [this message]
2025-07-10  3:43     ` Neeraj Upadhyay
2025-07-12 15:21       ` Borislav Petkov
2025-07-12 17:08         ` Neeraj Upadhyay
2025-07-12 18:46           ` Borislav Petkov
2025-07-13  2:11             ` Neeraj Upadhyay
2025-07-14 13:32             ` Sean Christopherson
2025-07-09  3:32 ` [RFC PATCH v8 16/35] x86/apic: Simplify bitwise operations on APIC bitmap Neeraj Upadhyay
2025-07-09 14:35   ` Sean Christopherson
2025-07-14 10:52     ` Borislav Petkov
2025-07-14 11:06       ` Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 17/35] x86/apic: Move apic_update_irq_cfg() calls to apic_update_vector() Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 18/35] x86/apic: Add new driver for Secure AVIC Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 19/35] x86/apic: Initialize Secure AVIC APIC backing page Neeraj Upadhyay
2025-07-15  4:49   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 20/35] x86/apic: Populate .read()/.write() callbacks of Secure AVIC driver Neeraj Upadhyay
2025-07-15  8:15   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 21/35] x86/apic: Initialize APIC ID for Secure AVIC Neeraj Upadhyay
2025-07-15  8:16   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 22/35] x86/apic: Add update_vector() callback for apic drivers Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 23/35] x86/apic: Add update_vector() callback for Secure AVIC Neeraj Upadhyay
2025-07-15 10:15   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 24/35] x86/apic: Add support to send IPI " Neeraj Upadhyay
2025-07-18  1:45   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 25/35] x86/apic: Support LAPIC timer " Neeraj Upadhyay
2025-07-18  2:14   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 26/35] x86/sev: Initialize VGIF for secondary VCPUs " Neeraj Upadhyay
2025-07-18  2:16   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 27/35] x86/apic: Add support to send NMI IPI " Neeraj Upadhyay
2025-07-18  2:57   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 28/35] x86/apic: Allow NMI to be injected from hypervisor " Neeraj Upadhyay
2025-07-18  2:58   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 29/35] x86/sev: Enable NMI support " Neeraj Upadhyay
2025-07-18  3:00   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 30/35] x86/apic: Read and write LVT* APIC registers from HV for SAVIC guests Neeraj Upadhyay
2025-07-18  3:08   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 31/35] x86/apic: Handle EOI writes for Secure AVIC guests Neeraj Upadhyay
2025-07-20  4:56   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 32/35] x86/apic: Add kexec support for Secure AVIC Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 33/35] x86/apic: Enable Secure AVIC in Control MSR Neeraj Upadhyay
2025-07-20  5:47   ` Tianyu Lan
2025-07-09  3:32 ` [RFC PATCH v8 34/35] x86/sev: Prevent SECURE_AVIC_CONTROL MSR interception for Secure AVIC guests Neeraj Upadhyay
2025-07-09  3:32 ` [RFC PATCH v8 35/35] x86/sev: Indicate SEV-SNP guest supports Secure AVIC Neeraj Upadhyay
2025-07-20  5:49   ` Tianyu Lan
2025-07-09 14:41 ` [RFC PATCH v8 00/35] AMD: Add Secure AVIC Guest Support Sean Christopherson
2025-07-09 21:41   ` Borislav Petkov
2025-07-10 23:08 ` Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aG59lcEc3ZBq8aHZ@google.com \
    --to=seanjc@google.com \
    --cc=David.Kaplan@amd.com \
    --cc=Neeraj.Upadhyay@amd.com \
    --cc=Santosh.Shukla@amd.com \
    --cc=Suravee.Suthikulpanit@amd.com \
    --cc=Thomas.Lendacky@amd.com \
    --cc=Vasant.Hegde@amd.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=huibo.wang@amd.com \
    --cc=kai.huang@intel.com \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=naveen.rao@amd.com \
    --cc=nikunj@amd.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).