-
Notifications
You must be signed in to change notification settings - Fork 19
Linux AMD Secure AVIC function support for OpenHCL kernel #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Linux AMD Secure AVIC function support for OpenHCL kernel #103
Conversation
Consolidate KVM's {REG,VEC}_POS() macros and lapic_vector_set_in_irr()'s
open coded equivalent logic in anticipation of the kernel gaining more
usage of vector => reg+bit lookups.
Use lapic_vector_set_in_irr()'s math as using divides for both the bit
number and register offset makes it easier to connect the dots, and for at
least one user, fixup_irqs(), "/ 32 * 0x10" generates ever so slightly
better code with gcc-14 (shaves a whole 3 bytes from the code stream):
((v) >> 5) << 4:
c1 ef 05 shr $0x5,%edi
c1 e7 04 shl $0x4,%edi
81 c7 00 02 00 00 add $0x200,%edi
(v) / 32 * 0x10:
c1 ef 05 shr $0x5,%edi
83 c7 20 add $0x20,%edi
c1 e7 04 shl $0x4,%edi
Keep KVM's tersely named macros as "wrappers" to avoid unnecessary churn
in KVM, and because the shorter names yield more readable code overall in
KVM.
The new macros type cast the vector parameter to "unsigned int". This is
required from better code generation for cases where an "int" is passed
to these macros in KVM code.
int v;
((v) >> 5) << 4:
c1 f8 05 sar $0x5,%eax
c1 e0 04 shl $0x4,%eax
((v) / 32 * 0x10):
85 ff test %edi,%edi
8d 47 1f lea 0x1f(%rdi),%eax
0f 49 c7 cmovns %edi,%eax
c1 f8 05 sar $0x5,%eax
c1 e0 04 shl $0x4,%eax
((unsigned int)(v) / 32 * 0x10):
c1 f8 05 sar $0x5,%eax
c1 e0 04 shl $0x4,%eax
(v) & (32 - 1):
89 f8 mov %edi,%eax
83 e0 1f and $0x1f,%eax
(v) % 32
89 fa mov %edi,%edx
c1 fa 1f sar $0x1f,%edx
c1 ea 1b shr $0x1b,%edx
8d 04 17 lea (%rdi,%rdx,1),%eax
83 e0 1f and $0x1f,%eax
29 d0 sub %edx,%eax
(unsigned int)(v) % 32:
89 f8 mov %edi,%eax
83 e0 1f and $0x1f,%eax
Overall kvm.ko text size is impacted if "unsigned int" is not used.
Bin Orig New (w/o unsigned int) New (w/ unsigned int)
lapic.o 28580 28772 28580
kvm.o 670810 671002 670810
kvm.ko 708079 708271 708079
No functional change intended.
[Neeraj: Type cast vec macro param to "unsigned int", provide data
in commit log on "unsigned int" requirement]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
In preparation for using apic_find_highest_vector() in Secure AVIC guest APIC driver, move it and associated macros to apic.h. No functional change intended. Acked-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Move the apic_get_reg(), apic_set_reg(), apic_get_reg64() and apic_set_reg64() helper functions to apic.h in order to reuse them in the Secure AVIC guest APIC driver in later patches to read/write registers from/to the APIC backing page. No functional change intended. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Acked-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Move apic_clear_vector() and apic_set_vector() helper functions to apic.h in order to reuse them in the Secure AVIC guest APIC driver in later patches to atomically set/clear vectors in the APIC backing page. No functional change intended. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Acked-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Move apic_test_vector() to apic.h in order to reuse it in the Secure AVIC guest APIC driver in later patches to test vector state in the APIC backing page. No functional change intended. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Acked-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Rename the 'reg_off' parameter of apic_{set|get}_reg() to 'reg' to
match other usages in apic.h.
No functional change intended.
Reviewed-by: Tianyu Lan <tiala@microsoft.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Signed-off-by: Tianyu Lan <tiala@microsoft.com>
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
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>
Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Use 'regs' as a contiguous linear bitmap for bitwise operations in
apic_{set|clear|test}_vector(). This makes the code simpler by eliminating
the need to determine the offset of the 32-bit register and the vector bit
location within that register prior to performing bitwise operations.
This change results in slight increase in generated code size for
gcc-14.2.
- Without change
apic_set_vector:
89 f8 mov %edi,%eax
83 e7 1f and $0x1f,%edi
c1 e8 05 shr $0x5,%eax
c1 e0 04 shl $0x4,%eax
48 01 c6 add %rax,%rsi
f0 48 0f ab 3e lock bts %rdi,(%rsi)
c3 ret
- With change
apic_set_vector:
89 f8 mov %edi,%eax
c1 e8 05 shr $0x5,%eax
8d 04 40 lea (%rax,%rax,2),%eax
c1 e0 05 shl $0x5,%eax
01 f8 add %edi,%eax
89 c0 mov %eax,%eax
f0 48 0f ab 3e lock bts %rax,(%rsi)
c3 ret
But, lapic.o text size (bytes) decreases with this change:
Obj Old-size New-size
lapic.o 28832 28768
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Signed-off-by: Tianyu Lan <tiala@microsoft.com>
All callers of apic_update_vector() also call apic_update_irq_cfg() after it. So, simplify the code by moving all such apic_update_irq_cfg() calls to apic_update_vector(). No functional change intended. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
The Secure AVIC feature provides SEV-SNP guests hardware acceleration for performance sensitive APIC accesses while securely managing the guest-owned APIC state through the use of a private APIC backing page. This helps prevent hypervisor from generating unexpected interrupts for a vCPU or otherwise violate architectural assumptions around APIC behavior. Add a new x2APIC driver that will serve as the base of the Secure AVIC support. It is initially the same as the x2APIC phys driver (without IPI callbacks), but will be modified as features of Secure AVIC are implemented. As the new driver does not implement Secure AVIC features yet, if the hypervisor sets the Secure AVIC bit in SEV_STATUS, maintain the existing behavior to enforce the guest termination. Co-developed-by: Kishon Vijay Abraham I <kvijayab@amd.com> Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
With Secure AVIC, the APIC backing page is owned and managed by guest. Allocate and initialize APIC backing page for all guest CPUs. The NPT entry for a vCPU's APIC backing page must always be present when the vCPU is running, in order for Secure AVIC to function. A VMEXIT_BUSY is returned on VMRUN and the vCPU cannot be resumed if the NPT entry for the APIC backing page is not present. To handle this, notify GPA of the vCPU's APIC backing page to the hypervisor by using the SVM_VMGEXIT_SECURE_AVIC GHCB protocol event. Before executing VMRUN, the hypervisor makes use of this information to make sure the APIC backing page is mapped in NPT. 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Add read() and write() APIC callback functions to read and write x2APIC registers directly from the guest APIC backing page of a vCPU. The x2APIC registers are mapped at an offset within the guest APIC backing page which is same as their x2APIC MMIO offset. Secure AVIC adds new registers such as ALLOWED_IRRs (which are at 4-byte offset within the IRR register offset range) and NMI_REQ to the APIC register space. When Secure AVIC is enabled, guest's rdmsr/wrmsr of APIC registers result in VC exception (for non-accelerated register accesses) with error code VMEXIT_AVIC_NOACCEL. The VC exception handler can read/write the x2APIC register in the guest APIC backing page to complete the rdmsr/wrmsr. Since doing this would increase the latency of accessing x2APIC registers, instead of doing rdmsr/wrmsr based reg accesses and handling reads/writes in VC exception, directly read/write APIC registers from/to the guest APIC backing page of the vCPU in read() and write() callbacks of the Secure AVIC APIC driver. 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Initialize the APIC ID in the Secure AVIC APIC backing page with the APIC_ID msr value read from Hypervisor. CPU topology evaluation later during boot would catch and report any duplicate APIC ID for two CPUs. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Add an update_vector() callback to allow APIC drivers to perform driver specific operations on external vector allocation/teardown on a CPU. This callback will be used in subsequent commits by Secure AVIC APIC driver to configure the vectors which a guest vCPU allows the hypervisor to send to it. As system vectors have fixed vector assignments and are not dynamically allocated, add apic_update_vector() public api to facilitate update_vector() callback invocation for them. This will be used for Secure AVIC enabled guests to allow the hypervisor to inject system vectors which are emulated by the hypervisor such as APIC timer vector and HYPERVISOR_CALLBACK_VECTOR. While at it, cleanup line break in apic_update_irq_cfg(). 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> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Add update_vector() callback to set/clear ALLOWED_IRR field in a vCPU's APIC backing page for vectors which are emulated by the hypervisor. The ALLOWED_IRR field indicates the interrupt vectors which the guest allows the hypervisor to inject (typically for emulated devices). Interrupt vectors used exclusively by the guest itself and the vectors which are not emulated by the hypervisor, such as IPI vectors, should not be set by the guest in the ALLOWED_IRR fields. As clearing/setting state of a vector will also be used in subsequent commits for other APIC regs (such as APIC_IRR update for sending IPI), add a common update_vector() in Secure AVIC driver. 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
With Secure AVIC only Self-IPI is accelerated. To handle all the other IPIs, add new callbacks for sending IPI. These callbacks write to the IRR of the target guest vCPU's APIC backing page and issue GHCB protocol MSR write event for the hypervisor to notify the target vCPU about the new interrupt request. For Secure AVIC GHCB APIC MSR writes, reuse GHCB msr handling code in vc_handle_msr() by exposing a sev-internal sev_es_ghcb_handle_msr(). 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Secure AVIC requires LAPIC timer to be emulated by the hypervisor. KVM already supports emulating LAPIC timer using hrtimers. In order to emulate LAPIC timer, APIC_LVTT, APIC_TMICT and APIC_TDCR register values need to be propagated to the hypervisor for arming the timer. APIC_TMCCT register value has to be read from the hypervisor, which is required for calibrating the APIC timer. So, read/write all APIC timer registers from/to the hypervisor. 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Secure AVIC requires VGIF to be configured in VMSA. Configure for secondary CPUs (the configuration for boot CPU is done by the hypervisor). Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Secure AVIC has introduced a new field in the APIC backing page "NmiReq" that has to be set by the guest to request a NMI IPI through APIC_ICR write. Add support to set NmiReq appropriately to send NMI IPI. Sending NMI IPI also requires Virtual NMI feature to be enabled in VINTRL_CTRL field in the VMSA. However, this would be added by a later commit after adding support for injecting NMI from the hypervisor. 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> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Secure AVIC requires "AllowedNmi" bit in the Secure AVIC Control MSR to be set for NMI to be injected from hypervisor. Set "AllowedNmi" bit in Secure AVIC Control MSR to allow NMI interrupts to be injected from hypervisor. Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Now that support to send NMI IPI and support to inject NMI from the hypervisor has been added, set V_NMI_ENABLE in VINTR_CTRL field of VMSA to enable NMI for Secure AVIC guests. Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Secure AVIC accelerates guest's EOI msr writes for edge-triggered interrupts. For level-triggered interrupts, EOI msr writes trigger VC exception with SVM_EXIT_AVIC_UNACCELERATED_ACCESS error code. To complete EOI handling, the VC exception handler would need to trigger a GHCB protocol MSR write event to notify the hypervisor about completion of the level-triggered interrupt. Hypervisor notification is required for cases like emulated IOAPIC, to complete and clear interrupt in the IOAPIC's interrupt state. However, VC exception handling adds extra performance overhead for APIC register writes. In addition, for Secure AVIC, some unaccelerated APIC register msr writes are trapped, whereas others are faulted. This results in additional complexity in VC exception handling for unacclerated APIC msr accesses. So, directly do a GHCB protocol based APIC EOI msr write from apic->eoi() callback for level-triggered interrupts. Use wrmsr for edge-triggered interrupts, so that hardware re-evaluates any pending interrupt which can be delivered to guest vCPU. For level- triggered interrupts, re-evaluation happens on return from VMGEXIT corresponding to the GHCB event for APIC EOI msr write. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Add a apic->teardown() callback to disable Secure AVIC before rebooting into the new kernel. This ensures that the new kernel does not access the old APIC backing page which was allocated by the previous kernel. Such accesses can happen if there are any APIC accesses done during guest boot before Secure AVIC driver probe is done by the new kernel (as Secure AVIC would have remained enabled in the Secure AVIC control msr). Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
With all the pieces in place now, enable Secure AVIC in Secure AVIC Control MSR. Any access to x2APIC MSRs are emulated by the hypervisor before Secure AVIC is enabled in the control MSR. Post Secure AVIC enablement, all x2APIC MSR accesses (whether accelerated by AVIC hardware or trapped as VC exception) operate on vCPU's APIC backing page. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Tianyu Lan <tiala@microsoft.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
When Secure AVIC is available, the AMD x2apic Secure AVIC driver will be selected. In that case, have hv_apic_init() return immediately without doing anything. Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
When Secure AVIC is enabled, VMBus driver should call x2apic Secure AVIC interface to allow Hyper-V to inject VMBus message interrupt. Reviewed-by: Michael Kelley <mhklinux@outlook.com> Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Hyper-V doesn't support auto-eoi with Secure AVIC. So set the HV_DEPRECATING_AEOI_RECOMMENDED flag to force writing the EOI register after handling an interrupt. Reviewed-by: Michael Kelley <mhklinux@outlook.com> Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
When Secure AVIC is enabled, call Secure AVIC function to allow Hyper-V to inject STIMER0 interrupt. Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Tianyu Lan <tiala@microsoft.com>
9918fc6 to
8058322
Compare
8058322 to
b71331b
Compare
Secure AVIC provides backing page to aid the guest in limiting which interrupt vectors can be injected into the guest. Hyper-V has specific hvcall to set backing page and call it in Secure AVIC driver. Signed-off-by: Tianyu Lan <tiala@microsoft.com>
Select AMD Secure AVIC driver in the CVM config file. Signed-off-by: Tianyu Lan <tiala@microsoft.com>
b71331b to
36616f6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements AMD Secure AVIC (Advanced Virtual Interrupt Controller) support for OpenHCL kernel running on SEV-SNP guests. Secure AVIC provides hardware acceleration for APIC operations and enables guest-controlled APIC state management to prevent hypervisor interference with interrupts.
- New x2APIC Secure AVIC driver with per-CPU APIC backing pages
- Hyper-V integration for APIC backing page registration via hypercalls
- Vector management infrastructure for interrupt tracking across APIC drivers
Reviewed Changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| include/linux/cc_platform.h | Adds CC_ATTR_SNP_SECURE_AVIC capability flag |
| include/asm-generic/mshyperv.h | Adds hv_enable_coco_interrupt function declaration |
| arch/x86/kernel/apic/x2apic_savic.c | New Secure AVIC x2APIC driver implementation |
| arch/x86/kernel/apic/vector.c | Updates vector management to use new APIC callbacks |
| arch/x86/hyperv/ivm.c | Adds hv_set_savic_backing_page hypercall implementation |
| drivers/hv/hv_common.c | Adds weak hv_enable_coco_interrupt stub |
| arch/x86/coco/sev/core.c | Adds Secure AVIC GHCB protocol support |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
I assume:
Will hit the "Approve" button once we clear that! Appreciate your help very much! |
36616f6 to
0c73b72
Compare
Secure AVIC is a new hardware feature in the AMD64 architecture that enables SEV-SNP guests to prevent the hypervisor from generating unexpected interrupts to a vCPU or violating architectural assumptions around APIC behavior.
Each vCPU has a guest-allocated APIC backing page of 4K size, maintaining the APIC state for that vCPU. The x2APIC MSRs are mapped at their corresponding x2APIC MMIO offset within the guest APIC backing page.
Integrate AMD Secure AVIC driver with Hyper-V specific API to set backing page. Hypervisor/Host pins guest APIC backing page after getting the page from guest.
This patchset is based on AMD Secure AVIC driver v8 patch set as based and add Hyper-V related patch and test on AMD Turin machine.