Add AMD Secure Nested Paging (SEV-SNP) Guest Support
Subsystems (11)
v12 cover Add AMD Secure Nested Paging (SEV-SNP) Guest Support
This part of Secure Encrypted Paging (SEV-SNP) series focuses on the changes required in a guest OS for SEV-SNP support.
SEV-SNP builds upon existing SEV and SEV-ES functionality while adding new hardware-based memory protections. SEV-SNP adds strong memory integrity protection to help prevent malicious hypervisor-based attacks like data replay, memory re-mapping and more in order to create an isolated memory encryption environment.
This series provides the basic building blocks to support booting the SEV-SNP VMs, it does not cover all the security enhancement introduced by the SEV-SNP such as interrupt protection.
Many of the integrity guarantees of SEV-SNP are enforced through a new structure called the Reverse Map Table (RMP). Adding a new page to SEV-SNP VM requires a 2-step process. First, the hypervisor assigns a page to the guest using the new RMPUPDATE instruction. This transitions the page to guest-invalid. Second, the guest validates the page using the new PVALIDATE instruction. The SEV-SNP VMs can use the new "Page State Change Request NAE" defined in the GHCB specification to ask hypervisor to add or remove page from the RMP table.
Each page assigned to the SEV-SNP VM can either be validated or unvalidated, as indicated by the Validated flag in the page's RMP entry. There are two approaches that can be taken for the page validation: Pre-validation and Lazy Validation.
Under pre-validation, the pages are validated prior to first use. And under lazy validation, pages are validated when first accessed. An access to a unvalidated page results in a #VC exception, at which time the exception handler may validate the page. Lazy validation requires careful tracking of the validated pages to avoid validating the same GPA more than once. The recently introduced "Unaccepted" memory type can be used to communicate the unvalidated memory ranges to the Guest OS.
At this time we only support the pre-validation, the OVMF guest BIOS validates the entire RAM before the control is handed over to the guest kernel. The early_set_memory_{encrypted,decrypted} and set_memory_{encrypted,decrypted} are enlightened to perform the page validation or invalidation while setting or clearing the encryption attribute from the page table.
This series does not provide support for the Interrupt security yet which will be added after the base support.
The complete branch is at https://github.com/AMDESE/linux/tree/sev-snp-v12
Patch 1-4 defines multiple VMSA save area to support SEV,SEV-ES and SEV-SNP guests. It is a pre-requisite for the SEV-SNP guest support, and included in the series for the completeness. These patch is queue'd here
https://git.kernel.org/pub/scm/virt/kvm/kvm.git, branch svm-for-snp.
Additional resources
---------------------
SEV-SNP whitepaper
https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf
APM 2: https://www.amd.com/system/files/TechDocs/24593.pdf
(section 15.36)
GHCB spec:
https://developer.amd.com/wp-content/resources/56421.pdf
SEV-SNP firmware specification:
https://developer.amd.com/sev/
v11: https://lore.kernel.org/all/[email protected]/
v10: https://lore.kernel.org/linux-mm/[email protected]/T/
v9: https://lore.kernel.org/linux-mm/[email protected]
v8: https://lore.kernel.org/lkml/[email protected]/
v7: https://lore.kernel.org/linux-mm/[email protected]/
v6: https://lore.kernel.org/linux-mm/[email protected]/
v5: https://lore.kernel.org/lkml/[email protected]/
Change since v11:
* Simplify the memory allocation for VMSA to address Dave Hansen feedback.
* Drop the unneeded memset for request and response buffer in the sevguest command handling.
* Make fw_err required for the SNP guest request API.
* Simplify the error code checking for SNP_GET_EXT_REPORT command handing to address Boris feedback.
* Rename the command line from "sev_debug" => "sev=debug" to dump the CPUID value.
Changes since v10:
* Rebase patches to x86/cc.
* Integerate the SNP page state change functions in x86_platform.guest_{prepare,finish} hook.
Changes since v9:
* Removed unnecessary checks on CPUID table contents, added kernel param to dump CPUID table during boot
* Added boot_{rd,wr}msr() helpers
* Renamed/refactored SNP CPUID code/definitions for clarity/consistency
* Re-worked comments for clarity and avoid redundancies
* Moved SNP CPUID table documentation to Documentation/virt/coco/sevguest.rst
* Documented cc_blob_address/acpi_rsdp_addr in zero-page.rst
Changes since v8:
* Setup the GHCB before taking the first #VC.
* Make the CC blob structure size invariant.
* Define the AP INIT macro and update the AP creation to use those macro instead of the hardcoded values.
* Expand the comments to cover some of previous feedbacks.
* Fix the commit messages based on the feedbacks.
* Multiple fixes/cleanup on cpuid patches (based on Boris and Dave feedback)
* drop is_efi64 return arguments in favor of a separate efi_get_type() helper.
* drop is_efi64 input arguments in favor of calling efi_get_type() as-needed.
* move acpi.c's kexec-specific handling into library code.
* fix stack protection for 32/64-bit builds.
* Export add_identity_map() to avoid SEV-specific code in ident_map_64.c.
* use snp_abort() when terminating via initial ccblob scan.
* fix the copyright header after the code refactor.
* remove code duplication whereever possible.
Changes since v7:
* sevguest: extend the get report structure to accept the vmpl from userspace.
* In the compressed path, move the GHCB protocol negotiation from VC handler
to sev_enable().
* sev_enable(): don't expect SEV bit in status MSR when cpuid bit is present, update comments.
* sme_enable(): call directly from head_64.S rather than as part of startup_64_setup_env, add comments
* snp_find_cc_blob(), sev_prep_identity_maps(): add missing 'static' keywords to function prototypes
Changes since v6:
* Add rmpadjust() helper to be used by AP creation and vmpl0 detect function.
* Clear the VM communication key if guest detects that hypervisor is modifying the SNP_GUEST_REQ response header.
* Move the per-cpu GHCB registration from first #VC to idt setup.
* Consolidate initial SEV/SME setup into a common entry point that gets called early enough to also be used for SEV-SNP CPUID table setup.
* SNP CPUID: separate initial SEV-SNP feature detection out into standalone snp_init() routines, then add CPUID table setup to it as a separate patch.
* SNP CPUID: fix boot issue with Seabios due to ACPI relying on certain EFI config table lookup failures as fallthrough cases rather than error cases.
* SNP CPUID: drop the use of a separate init routines to handle pointer fixups after switching to kernel virtual addresses, instead use a helper that uses RIP-relative addressing to access CPUID table when either on identity mapping or kernel virtual addresses.
Changes since v5:
* move the seqno allocation in the sevguest driver.
* extend snp_issue_guest_request() to accept the exit_info to simplify the logic.
* use smaller structure names based on feedback.
* explicitly clear the memory after the SNP guest request is completed.
* cpuid validation: use a local copy of cpuid table instead of keeping firmware table mapped throughout boot.
* cpuid validation: coding style fix-ups and refactor cpuid-related helpers as suggested.
* cpuid validation: drop a number of BOOT_COMPRESSED-guarded defs/declarations by moving things like snp_cpuid_init*() out of sev-shared.c and keeping only the common bits there.
* Break up EFI config table helpers and related acpi.c changes into separate patches.
* re-enable stack protection for 32-bit kernels as well, not just 64-bit
Changes since v4:
* Address the cpuid specific review comment
* Simplified the macro based on the review feedback
* Move macro definition to the patch that needs it
* Fix the issues reported by the checkpath
* Address the AP creation specific review comment
Changes since v3:
* Add support to use the PSP filtered CPUID.
* Add support for the extended guest request.
* Move sevguest driver in driver/virt/coco.
* Add documentation for sevguest ioctl.
* Add support to check the vmpl0.
* Pass the VM encryption key and id to be used for encrypting guest messages through the platform drv data.
* Multiple cleanup and fixes to address the review feedbacks.
Changes since v2:
* Add support for AP startup using SNP specific vmgexit.
* Add snp_prep_memory() helper.
* Drop sev_snp_active() helper.
* Add sev_feature_enabled() helper to check which SEV feature is active.
* Sync the SNP guest message request header with latest SNP FW spec.
* Multiple cleanup and fixes to address the review feedbacks.
Changes since v1:
* Integerate the SNP support in sev.{ch}.
* Add support to query the hypervisor feature and detect whether SNP is supported.
* Define Linux specific reason code for the SNP guest termination.
* Extend the setup_header provide a way for hypervisor to pass secret and cpuid page.
* Add support to create a platform device and driver to query the attestation report and the derive a key.
* Multiple cleanup and fixes to address Boris's review fedback.
Brijesh Singh (20):
KVM: SVM: Define sev_features and vmpl field in the VMSA x86/mm: Extend cc_attr to include AMD SEV-SNP
x86/sev: Define the Linux specific guest termination reasons x86/sev: Save the negotiated GHCB version
x86/sev: Check SEV-SNP features support
x86/sev: Add a helper for the PVALIDATE instruction x86/sev: Check the vmpl level
x86/compressed: Add helper for validating pages in the decompression
stage
x86/compressed: Register GHCB memory when SEV-SNP is active x86/sev: Register GHCB memory when SEV-SNP is active x86/sev: Add helper for validating pages in early enc attribute
changes
x86/kernel: Make the .bss..decrypted section shared in RMP table x86/kernel: Validate ROM memory before accessing when SEV-SNP is
active
x86/mm: Validate memory when changing the C-bit
x86/boot: Add Confidential Computing type to setup_data x86/sev: Provide support for SNP guest request NAEs x86/sev: Register SEV-SNP guest request platform device
virt: Add SEV-SNP guest driver
virt: sevguest: Add support to derive key
virt: sevguest: Add support to get extended report
Michael Roth (22):
x86/boot: Introduce helpers for MSR reads/writes
x86/boot: Use MSR read/write helpers instead of inline assembly x86/compressed/64: Detect/setup SEV/SME features earlier in boot x86/sev: Detect/setup SEV/SME features earlier in boot x86/head/64: Re-enable stack protection x86/compressed/acpi: Move EFI detection to helper x86/compressed/acpi: Move EFI system table lookup to helper x86/compressed/acpi: Move EFI config table lookup to helper x86/compressed/acpi: Move EFI vendor table lookup to helper x86/compressed/acpi: Move EFI kexec handling into common code
KVM: x86: Move lookup of indexed CPUID leafs to helper x86/sev: Move MSR-based VMGEXITs for CPUID to helper x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers x86/boot: Add a pointer to Confidential Computing blob in bootparams x86/compressed: Add SEV-SNP feature detection/setup x86/compressed: Use firmware-validated CPUID leaves for SEV-SNP guests x86/compressed: Export and rename add_identity_map() x86/compressed/64: Add identity mapping for Confidential Computing
blob
x86/sev: Add SEV-SNP feature detection/setup
x86/sev: Use firmware-validated CPUID for SEV-SNP guests x86/sev: add sev=debug cmdline option to dump SNP CPUID table
virt: sevguest: Add documentation for SEV-SNP CPUID Enforcement
Tom Lendacky (4):
KVM: SVM: Create a separate mapping for the SEV-ES save area
KVM: SVM: Create a separate mapping for the GHCB save area
KVM: SVM: Update the SEV-ES save area mapping x86/sev: Use SEV-SNP AP creation to start secondary CPUs
.../admin-guide/kernel-parameters.txt | 2 + Documentation/virt/coco/sevguest.rst | 155 ++++ Documentation/virt/index.rst | 1 + Documentation/x86/x86_64/boot-options.rst | 14 + Documentation/x86/zero-page.rst | 2 + arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/acpi.c | 173 +--- arch/x86/boot/compressed/efi.c | 238 +++++ arch/x86/boot/compressed/head_64.S | 37 +- arch/x86/boot/compressed/ident_map_64.c | 39 +- arch/x86/boot/compressed/idt_64.c | 18 +- arch/x86/boot/compressed/mem_encrypt.S | 36 - arch/x86/boot/compressed/misc.h | 55 +- arch/x86/boot/compressed/sev.c | 263 +++++- arch/x86/boot/cpucheck.c | 30 +- arch/x86/boot/msr.h | 28 + arch/x86/coco/core.c | 3 + arch/x86/include/asm/bootparam_utils.h | 1 + arch/x86/include/asm/cpuid.h | 34 + arch/x86/include/asm/msr-index.h | 2 + arch/x86/include/asm/msr.h | 11 +- arch/x86/include/asm/setup.h | 1 - arch/x86/include/asm/sev-common.h | 82 ++ arch/x86/include/asm/sev.h | 102 ++- arch/x86/include/asm/shared/msr.h | 15 + arch/x86/include/asm/svm.h | 171 +++- arch/x86/include/uapi/asm/bootparam.h | 4 +- arch/x86/include/uapi/asm/svm.h | 13 + arch/x86/kernel/Makefile | 2 - arch/x86/kernel/cpu/common.c | 4 + arch/x86/kernel/head64.c | 29 +- arch/x86/kernel/head_64.S | 37 +- arch/x86/kernel/probe_roms.c | 13 +- arch/x86/kernel/sev-shared.c | 529 ++++++++++- arch/x86/kernel/sev.c | 834 +++++++++++++++++- arch/x86/kernel/smpboot.c | 3 + arch/x86/kvm/cpuid.c | 19 +- arch/x86/kvm/svm/sev.c | 24 +- arch/x86/kvm/svm/svm.c | 4 +- arch/x86/kvm/svm/svm.h | 2 +- arch/x86/mm/mem_encrypt.c | 4 + arch/x86/mm/mem_encrypt_amd.c | 71 +- arch/x86/mm/mem_encrypt_identity.c | 8 + drivers/virt/Kconfig | 3 + drivers/virt/Makefile | 1 + drivers/virt/coco/sevguest/Kconfig | 14 + drivers/virt/coco/sevguest/Makefile | 2 + drivers/virt/coco/sevguest/sevguest.c | 740 ++++++++++++++++ drivers/virt/coco/sevguest/sevguest.h | 98 ++ include/linux/cc_platform.h | 8 + include/linux/efi.h | 1 + include/uapi/linux/sev-guest.h | 80 ++ 52 files changed, 3688 insertions(+), 373 deletions(-) create mode 100644 Documentation/virt/coco/sevguest.rst create mode 100644 arch/x86/boot/compressed/efi.c create mode 100644 arch/x86/boot/msr.h create mode 100644 arch/x86/include/asm/cpuid.h create mode 100644 arch/x86/include/asm/shared/msr.h create mode 100644 drivers/virt/coco/sevguest/Kconfig create mode 100644 drivers/virt/coco/sevguest/Makefile create mode 100644 drivers/virt/coco/sevguest/sevguest.c create mode 100644 drivers/virt/coco/sevguest/sevguest.h create mode 100644 include/uapi/linux/sev-guest.h
Signature · 1 line
2.25.1
PATCH v12 1/46 KVM: SVM: Define sev_features and vmpl field in the VMSA
The hypervisor uses the sev_features field (offset 3B0h) in the Save State Area to control the SEV-SNP guest features such as SNPActive, vTOM, ReflectVC etc. An SEV-SNP guest can read the SEV_FEATURES fields through the SEV_STATUS MSR.
While at it, update the dump_vmcb() to log the VMPL level.
See APM2 Table 15-34 and B-4 for more details.
--- arch/x86/include/asm/svm.h | 6 ++++-- arch/x86/kvm/svm/svm.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-)
arch/x86/include/asm/svm.h +4 -2
@@ -274,7 +274,8 @@ struct vmcb_save_area {struct vmcb_seg ldtr;struct vmcb_seg idtr;struct vmcb_seg tr; -u8 reserved_1[43 ]; +u8 reserved_1[42 ]; +u8 vmpl;u8 cpl;u8 reserved_2[4 ];u64 efer;
@@ -339,7 +340,8 @@ struct vmcb_save_area {u64 sw_exit_info_1;u64 sw_exit_info_2;u64 sw_scratch; -u8 reserved_11[56 ]; +u64 sev_features; +u8 reserved_11[48 ];u64 xcr0;u8 valid_bitmap[16 ];u64 x87_state_gpa;
arch/x86/kvm/svm/svm.c +2 -2
@@ -3118,8 +3118,8 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)"tr:" , save01->tr.selector, save01->tr.attrib, save01->tr.limit, save01->tr.base); -pr_err ("cpl: %d efer: %016llx\n" , - save->cpl, save->efer); +pr_err ("vmpl: %d cpl: %d efer: %016llx\n" , + save->vmpl, save->cpl, save->efer);pr_err ("%-15s %016llx %-13s %016llx\n" ,"cr0:" , save->cr0,"cr2:" , save->cr2); pr_err("%-15s %016llx %-13s %016llx\n",
Signature · 1 line
2.25.1
[tip: x86/sev] KVM: SVM: Define sev_features and VMPL field in the VMSA
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 046f773be106ec8eb92b13414c90f8e279deffe0 Gitweb: https://git.kernel.org/tip/046f773be106ec8eb92b13414c90f8e279deffe0 Author: Brijesh Singh <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:11 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Tue, 05 Apr 2022 19:09:27 +02:00
KVM: SVM: Define sev_features and VMPL field in the VMSA
The hypervisor uses the sev_features field (offset 3B0h) in the Save State Area to control the SEV-SNP guest features such as SNPActive, vTOM, ReflectVC etc. An SEV-SNP guest can read the sev_features field through the SEV_STATUS MSR.
While at it, update dump_vmcb() to log the VMPL level.
See APM2 Table 15-34 and B-4 for more details.
--- arch/x86/include/asm/svm.h | 6 ++++-- arch/x86/kvm/svm/svm.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-)
arch/x86/include/asm/svm.h +4 -2
@@ -282,7 +282,8 @@ struct vmcb_save_area {struct vmcb_seg ldtr;struct vmcb_seg idtr;struct vmcb_seg tr; -u8 reserved_1[43 ]; +u8 reserved_1[42 ]; +u8 vmpl;u8 cpl;u8 reserved_2[4 ];u64 efer;
@@ -347,7 +348,8 @@ struct vmcb_save_area {u64 sw_exit_info_1;u64 sw_exit_info_2;u64 sw_scratch; -u8 reserved_11[56 ]; +u64 sev_features; +u8 reserved_11[48 ];u64 xcr0;u8 valid_bitmap[16 ];u64 x87_state_gpa;
arch/x86/kvm/svm/svm.c +2 -2
@@ -3117,8 +3117,8 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)"tr:" , save01->tr.selector, save01->tr.attrib, save01->tr.limit, save01->tr.base); -pr_err ("cpl: %d efer: %016llx\n" , - save->cpl, save->efer); +pr_err ("vmpl: %d cpl: %d efer: %016llx\n" , + save->vmpl, save->cpl, save->efer);pr_err ("%-15s %016llx %-13s %016llx\n" ,"cr0:" , save->cr0,"cr2:" , save->cr2); pr_err("%-15s %016llx %-13s %016llx\n",
PATCH v12 2/46 KVM: SVM: Create a separate mapping for the SEV-ES save area
In reply to Brijesh SinghFrom: Tom Lendacky <[email protected]>
The save area for SEV-ES/SEV-SNP guests, as used by the hardware, is different from the save area of a non SEV-ES/SEV-SNP guest.
This is the first step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create an SEV-ES/SEV-SNP save area and adjust usage to the new save area definition where needed.
--- arch/x86/include/asm/svm.h | 87 +++++++++++++++++++++++++++++--------- arch/x86/kvm/svm/sev.c | 24 +++++------ arch/x86/kvm/svm/svm.h | 2 +- 3 files changed, 80 insertions(+), 33 deletions(-)
arch/x86/include/asm/svm.h +67 -20
@@ -263,6 +263,7 @@ struct vmcb_seg {u64 base; } __packed; +/* Save area definition for legacy and SEV-MEM guests */ struct vmcb_save_area {struct vmcb_seg es;struct vmcb_seg cs;
@@ -279,8 +280,58 @@ struct vmcb_save_area {u8 cpl;u8 reserved_2[4 ];u64 efer; +u8 reserved_3[112 ]; +u64 cr4; +u64 cr3; +u64 cr0; +u64 dr7; +u64 dr6; +u64 rflags; +u64 rip; +u8 reserved_4[88 ]; +u64 rsp; +u64 s_cet; +u64 ssp; +u64 isst_addr; +u64 rax; +u64 star; +u64 lstar; +u64 cstar; +u64 sfmask; +u64 kernel_gs_base; +u64 sysenter_cs; +u64 sysenter_esp; +u64 sysenter_eip; +u64 cr2; +u8 reserved_5[32 ]; +u64 g_pat; +u64 dbgctl; +u64 br_from; +u64 br_to; +u64 last_excp_from; +u64 last_excp_to; +u8 reserved_6[72 ]; +u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ +} __packed; + +/* Save area definition for SEV-ES and SEV-SNP guests */ +struct sev_es_save_area { +struct vmcb_seg es; +struct vmcb_seg cs; +struct vmcb_seg ss; +struct vmcb_seg ds; +struct vmcb_seg fs; +struct vmcb_seg gs; +struct vmcb_seg gdtr; +struct vmcb_seg ldtr; +struct vmcb_seg idtr; +struct vmcb_seg tr; +u8 reserved_1[43 ]; +u8 cpl; +u8 reserved_2[4 ]; +u64 efer;u8 reserved_3[104 ]; -u64 xss;/* Valid for SEV-ES only */ +u64 xss;u64 cr4;u64 cr3;u64 cr0;
@@ -308,22 +359,14 @@ struct vmcb_save_area {u64 br_to;u64 last_excp_from;u64 last_excp_to; - -/* -* The following part of the save area is valid only for -* SEV-ES guests when referenced through the GHCB or for -* saving to the host save area. -*/ -u8 reserved_7[72 ]; -u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ -u8 reserved_7b[4 ]; +u8 reserved_7[80 ];u32 pkru; -u8 reserved_7a[20 ]; -u64 reserved_8;/* rax already available at 0x01f8 */ +u8 reserved_9[20 ]; +u64 reserved_10;/* rax already available at 0x01f8 */ u64 rcx;u64 rdx;u64 rbx; -u64 reserved_9;/* rsp already available at 0x01d8 */ +u64 reserved_11;/* rsp already available at 0x01d8 */ u64 rbp;u64 rsi;u64 rdi;
@@ -335,23 +378,25 @@ struct vmcb_save_area {u64 r13;u64 r14;u64 r15; -u8 reserved_10[16 ]; +u8 reserved_12[16 ];u64 sw_exit_code;u64 sw_exit_info_1;u64 sw_exit_info_2;u64 sw_scratch;u64 sev_features; -u8 reserved_11[48 ]; +u8 reserved_13[48 ];u64 xcr0;u8 valid_bitmap[16 ];u64 x87_state_gpa; } __packed; +#define GHCB_SHARED_BUF_SIZE 2032 +struct ghcb { -struct vmcb_save_area save; -u8 reserved_save[2048 -sizeof (struct vmcb_save_area )]; +struct sev_es_save_area save; +u8 reserved_save[2048 -sizeof (struct sev_es_save_area )]; -u8 shared_buffer[2032 ]; +u8 shared_buffer[GHCB_SHARED_BUF_SIZE ];u8 reserved_1[10 ];u16 protocol_version;/* negotiated SEV-ES/GHCB protocol version */
@@ -359,13 +404,15 @@ struct ghcb { } __packed; -#define EXPECTED_VMCB_SAVE_AREA_SIZE 1032 +#define EXPECTED_VMCB_SAVE_AREA_SIZE 740 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZEstatic inline void __unused_size_checks (void ) {BUILD_BUG_ON (sizeof (struct vmcb_save_area ) !=EXPECTED_VMCB_SAVE_AREA_SIZE ); +BUILD_BUG_ON (sizeof (struct sev_es_save_area ) !=EXPECTED_SEV_ES_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct vmcb_control_area ) !=EXPECTED_VMCB_CONTROL_AREA_SIZE );BUILD_BUG_ON (sizeof (struct ghcb ) !=EXPECTED_GHCB_SIZE ); }
@@ -435,7 +482,7 @@ struct vmcb {/* GHCB Accessor functions */ #define GHCB_BITMAP_IDX (field) \ - (offsetof(struct vmcb_save_area, field) / sizeof(u64)) + (offsetof(struct sev_es_save_area, field) / sizeof(u64))#define DEFINE_GHCB_ACCESSORS (field) \ static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb) \
arch/x86/kvm/svm/sev.c +12 -12
@@ -558,12 +558,20 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)static int sev_es_sync_vmsa (struct vcpu_svm *svm) { -struct vmcb_save_area *save = &svm->vmcb->save; +struct sev_es_save_area *save = svm->sev_es.vmsa;/* Check some debug related fields before encrypting the VMSA */ -if (svm->vcpu.guest_debug || (save->dr7 & ~DR7_FIXED_1 )) +if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1 ))return -EINVAL ; +/* +* SEV-ES will use a VMSA that is pointed to by the VMCB, not +* the traditional VMSA that is part of the VMCB. Copy the +* traditional VMSA as it has been built so far (in prep +* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. +*/ +memcpy (save, &svm->vmcb->save,sizeof (svm->vmcb->save)); +/* Sync registgers */ save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX ]; save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX ];
@@ -591,14 +599,6 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->xss = svm->vcpu.arch.ia32_xss; save->dr6 = svm->vcpu.arch.dr6; -/* -* SEV-ES will use a VMSA that is pointed to by the VMCB, not -* the traditional VMSA that is part of the VMCB. Copy the -* traditional VMSA as it has been built so far (in prep -* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. -*/ -memcpy (svm->sev_es.vmsa, save,sizeof (*save)); -return 0 ; }
@@ -2910,7 +2910,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)void sev_es_prepare_guest_switch (struct vcpu_svm *svm,unsigned int cpu) {struct svm_cpu_data *sd =per_cpu (svm_data, cpu); -struct vmcb_save_area *hostsa; +struct sev_es_save_area *hostsa;/* * As an SEV-ES guest, hardware will restore the host state on VMEXIT,
@@ -2920,7 +2920,7 @@ void sev_es_prepare_guest_switch(struct vcpu_svm *svm, unsigned int cpu)vmsave (__sme_page_pa (sd->save_area));/* XCR0 is restored on VMEXIT, save the current host value */ - hostsa = (struct vmcb_save_area *)(page_address (sd->save_area) +0x400 ); + hostsa = (struct sev_es_save_area *)(page_address (sd->save_area) +0x400 ); hostsa->xcr0 =xgetbv (XCR_XFEATURE_ENABLED_MASK );/* PKRU is restored on VMEXIT, save the current host value */
arch/x86/kvm/svm/svm.h +1 -1
@@ -167,7 +167,7 @@ struct svm_nested_state {struct vcpu_sev_es_state {/* SEV-ES support */ -struct vmcb_save_area *vmsa; +struct sev_es_save_area *vmsa;struct ghcb *ghcb;struct kvm_host_map ghcb_map;bool received_first_sipi;
Signature · 1 line
2.25.1
PATCH v12 1/1 KVM: SVM: Create a separate mapping for the SEV-ES save area
From: Tom Lendacky <[email protected]>
The save area for SEV-ES/SEV-SNP guests, as used by the hardware, is different from the save area of a non SEV-ES/SEV-SNP guest.
This is the first step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create an SEV-ES/SEV-SNP save area and adjust usage to the new save area definition where needed.
---
Hi Paolo,
Now there is a conflict when applying this patch on 5.18-rc1. Please use the updated patch when merging the first four patches from the series.
thanks
arch/x86/include/asm/svm.h | 87 +++++++++++++++++++++++++++++--------- arch/x86/kvm/svm/sev.c | 22 +++++----- arch/x86/kvm/svm/svm.c | 4 +- arch/x86/kvm/svm/svm.h | 4 +- 4 files changed, 82 insertions(+), 35 deletions(-)
arch/x86/include/asm/svm.h +67 -20
@@ -271,6 +271,7 @@ struct vmcb_seg {u64 base; } __packed; +/* Save area definition for legacy and SEV-MEM guests */ struct vmcb_save_area {struct vmcb_seg es;struct vmcb_seg cs;
@@ -287,8 +288,58 @@ struct vmcb_save_area {u8 cpl;u8 reserved_2[4 ];u64 efer; +u8 reserved_3[112 ]; +u64 cr4; +u64 cr3; +u64 cr0; +u64 dr7; +u64 dr6; +u64 rflags; +u64 rip; +u8 reserved_4[88 ]; +u64 rsp; +u64 s_cet; +u64 ssp; +u64 isst_addr; +u64 rax; +u64 star; +u64 lstar; +u64 cstar; +u64 sfmask; +u64 kernel_gs_base; +u64 sysenter_cs; +u64 sysenter_esp; +u64 sysenter_eip; +u64 cr2; +u8 reserved_5[32 ]; +u64 g_pat; +u64 dbgctl; +u64 br_from; +u64 br_to; +u64 last_excp_from; +u64 last_excp_to; +u8 reserved_6[72 ]; +u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ +} __packed; + +/* Save area definition for SEV-ES and SEV-SNP guests */ +struct sev_es_save_area { +struct vmcb_seg es; +struct vmcb_seg cs; +struct vmcb_seg ss; +struct vmcb_seg ds; +struct vmcb_seg fs; +struct vmcb_seg gs; +struct vmcb_seg gdtr; +struct vmcb_seg ldtr; +struct vmcb_seg idtr; +struct vmcb_seg tr; +u8 reserved_1[43 ]; +u8 cpl; +u8 reserved_2[4 ]; +u64 efer;u8 reserved_3[104 ]; -u64 xss;/* Valid for SEV-ES only */ +u64 xss;u64 cr4;u64 cr3;u64 cr0;
@@ -316,22 +367,14 @@ struct vmcb_save_area {u64 br_to;u64 last_excp_from;u64 last_excp_to; - -/* -* The following part of the save area is valid only for -* SEV-ES guests when referenced through the GHCB or for -* saving to the host save area. -*/ -u8 reserved_7[72 ]; -u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ -u8 reserved_7b[4 ]; +u8 reserved_7[80 ];u32 pkru; -u8 reserved_7a[20 ]; -u64 reserved_8;/* rax already available at 0x01f8 */ +u8 reserved_9[20 ]; +u64 reserved_10;/* rax already available at 0x01f8 */ u64 rcx;u64 rdx;u64 rbx; -u64 reserved_9;/* rsp already available at 0x01d8 */ +u64 reserved_11;/* rsp already available at 0x01d8 */ u64 rbp;u64 rsi;u64 rdi;
@@ -343,23 +386,25 @@ struct vmcb_save_area {u64 r13;u64 r14;u64 r15; -u8 reserved_10[16 ]; +u8 reserved_12[16 ];u64 sw_exit_code;u64 sw_exit_info_1;u64 sw_exit_info_2;u64 sw_scratch;u64 sev_features; -u8 reserved_11[48 ]; +u8 reserved_13[48 ];u64 xcr0;u8 valid_bitmap[16 ];u64 x87_state_gpa; } __packed; +#define GHCB_SHARED_BUF_SIZE 2032 +struct ghcb { -struct vmcb_save_area save; -u8 reserved_save[2048 -sizeof (struct vmcb_save_area )]; +struct sev_es_save_area save; +u8 reserved_save[2048 -sizeof (struct sev_es_save_area )]; -u8 shared_buffer[2032 ]; +u8 shared_buffer[GHCB_SHARED_BUF_SIZE ];u8 reserved_1[10 ];u16 protocol_version;/* negotiated SEV-ES/GHCB protocol version */
@@ -367,13 +412,15 @@ struct ghcb { } __packed; -#define EXPECTED_VMCB_SAVE_AREA_SIZE 1032 +#define EXPECTED_VMCB_SAVE_AREA_SIZE 740 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZEstatic inline void __unused_size_checks (void ) {BUILD_BUG_ON (sizeof (struct vmcb_save_area ) !=EXPECTED_VMCB_SAVE_AREA_SIZE ); +BUILD_BUG_ON (sizeof (struct sev_es_save_area ) !=EXPECTED_SEV_ES_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct vmcb_control_area ) !=EXPECTED_VMCB_CONTROL_AREA_SIZE );BUILD_BUG_ON (sizeof (struct ghcb ) !=EXPECTED_GHCB_SIZE ); }
@@ -443,7 +490,7 @@ struct vmcb {/* GHCB Accessor functions */ #define GHCB_BITMAP_IDX (field) \ - (offsetof(struct vmcb_save_area, field) / sizeof(u64)) + (offsetof(struct sev_es_save_area, field) / sizeof(u64))#define DEFINE_GHCB_ACCESSORS (field) \ static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb) \
arch/x86/kvm/svm/sev.c +11 -11
@@ -559,12 +559,20 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)static int sev_es_sync_vmsa (struct vcpu_svm *svm) { -struct vmcb_save_area *save = &svm->vmcb->save; +struct sev_es_save_area *save = svm->sev_es.vmsa;/* Check some debug related fields before encrypting the VMSA */ -if (svm->vcpu.guest_debug || (save->dr7 & ~DR7_FIXED_1 )) +if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1 ))return -EINVAL ; +/* +* SEV-ES will use a VMSA that is pointed to by the VMCB, not +* the traditional VMSA that is part of the VMCB. Copy the +* traditional VMSA as it has been built so far (in prep +* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. +*/ +memcpy (save, &svm->vmcb->save,sizeof (svm->vmcb->save)); +/* Sync registgers */ save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX ]; save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX ];
@@ -592,14 +600,6 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->xss = svm->vcpu.arch.ia32_xss; save->dr6 = svm->vcpu.arch.dr6; -/* -* SEV-ES will use a VMSA that is pointed to by the VMCB, not -* the traditional VMSA that is part of the VMCB. Copy the -* traditional VMSA as it has been built so far (in prep -* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. -*/ -memcpy (svm->sev_es.vmsa, save,sizeof (*save)); -return 0 ; }
@@ -2932,7 +2932,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm) sev_enc_bit)); } -void sev_es_prepare_switch_to_guest (struct vmcb_save_area *hostsa) +void sev_es_prepare_switch_to_guest (struct sev_es_save_area *hostsa) {/* * As an SEV-ES guest, hardware will restore the host state on VMEXIT,
arch/x86/kvm/svm/svm.c +2 -2
@@ -1270,8 +1270,8 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)*/ vmsave (__sme_page_pa (sd->save_area));if (sev_es_guest (vcpu->kvm)) { -struct vmcb_save_area *hostsa; - hostsa = (struct vmcb_save_area *)(page_address (sd->save_area) +0x400 ); +struct sev_es_save_area *hostsa; + hostsa = (struct sev_es_save_area *)(page_address (sd->save_area) +0x400 );sev_es_prepare_switch_to_guest (hostsa); }
arch/x86/kvm/svm/svm.h +2 -2
@@ -181,7 +181,7 @@ struct svm_nested_state {struct vcpu_sev_es_state {/* SEV-ES support */ -struct vmcb_save_area *vmsa; +struct sev_es_save_area *vmsa;struct ghcb *ghcb;struct kvm_host_map ghcb_map;bool received_first_sipi;
@@ -620,7 +620,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);void sev_es_init_vmcb (struct vcpu_svm *svm);void sev_es_vcpu_reset (struct vcpu_svm *svm);void sev_vcpu_deliver_sipi_vector (struct kvm_vcpu *vcpu,u8 vector); -void sev_es_prepare_switch_to_guest (struct vmcb_save_area *hostsa); +void sev_es_prepare_switch_to_guest (struct sev_es_save_area *hostsa);void sev_es_unmap_ghcb (struct vcpu_svm *svm);/* vmenter.S */
Signature · 1 line
2.25.1
Borislav Petkov
maintainerRe: [PATCH v12 2.1/46] KVM: SVM: Create a separate mapping for the SEV-ES save area
Quoted 13 lines · Brijesh Singh
From: Tom Lendacky <[email protected]>
The save area for SEV-ES/SEV-SNP guests, as used by the hardware, is different from the save area of a non SEV-ES/SEV-SNP guest.
This is the first step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create an SEV-ES/SEV-SNP save area and adjust usage to the new save area definition where needed.
Reviewed-by Venu Busireddy <[email protected]>Signed-off-by Tom Lendacky <[email protected]>Signed-off-by Brijesh Singh <[email protected]>
Quoted 7 lines
---
Hi Paolo,
Now there is a conflict when applying this patch on 5.18-rc1. Please use the updated patch when merging the first four patches from the series.
Right, or if you'd prefer I carried them through the tip tree, lemme know.
Thx.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette[tip: x86/sev] KVM: SVM: Create a separate mapping for the SEV-ES save area
In reply to Brijesh SinghThe following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 3dd2775b74c9b1b01d19805877ab45bc47c4a5a5 Gitweb: https://git.kernel.org/tip/3dd2775b74c9b1b01d19805877ab45bc47c4a5a5 Author: Tom Lendacky <[email protected]> AuthorDate: Tue, 05 Apr 2022 13:27:43 -05:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 12:08:40 +02:00
KVM: SVM: Create a separate mapping for the SEV-ES save area
The save area for SEV-ES/SEV-SNP guests, as used by the hardware, is different from the save area of a non SEV-ES/SEV-SNP guest.
This is the first step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create an SEV-ES/SEV-SNP save area and adjust usage to the new save area definition where needed.
--- arch/x86/include/asm/svm.h | 87 ++++++++++++++++++++++++++++--------- arch/x86/kvm/svm/sev.c | 22 ++++----- arch/x86/kvm/svm/svm.c | 4 +- arch/x86/kvm/svm/svm.h | 4 +- 4 files changed, 82 insertions(+), 35 deletions(-)
arch/x86/include/asm/svm.h +67 -20
@@ -271,6 +271,7 @@ struct vmcb_seg {u64 base; } __packed; +/* Save area definition for legacy and SEV-MEM guests */ struct vmcb_save_area {struct vmcb_seg es;struct vmcb_seg cs;
@@ -287,8 +288,58 @@ struct vmcb_save_area {u8 cpl;u8 reserved_2[4 ];u64 efer; +u8 reserved_3[112 ]; +u64 cr4; +u64 cr3; +u64 cr0; +u64 dr7; +u64 dr6; +u64 rflags; +u64 rip; +u8 reserved_4[88 ]; +u64 rsp; +u64 s_cet; +u64 ssp; +u64 isst_addr; +u64 rax; +u64 star; +u64 lstar; +u64 cstar; +u64 sfmask; +u64 kernel_gs_base; +u64 sysenter_cs; +u64 sysenter_esp; +u64 sysenter_eip; +u64 cr2; +u8 reserved_5[32 ]; +u64 g_pat; +u64 dbgctl; +u64 br_from; +u64 br_to; +u64 last_excp_from; +u64 last_excp_to; +u8 reserved_6[72 ]; +u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ +} __packed; + +/* Save area definition for SEV-ES and SEV-SNP guests */ +struct sev_es_save_area { +struct vmcb_seg es; +struct vmcb_seg cs; +struct vmcb_seg ss; +struct vmcb_seg ds; +struct vmcb_seg fs; +struct vmcb_seg gs; +struct vmcb_seg gdtr; +struct vmcb_seg ldtr; +struct vmcb_seg idtr; +struct vmcb_seg tr; +u8 reserved_1[43 ]; +u8 cpl; +u8 reserved_2[4 ]; +u64 efer;u8 reserved_3[104 ]; -u64 xss;/* Valid for SEV-ES only */ +u64 xss;u64 cr4;u64 cr3;u64 cr0;
@@ -316,22 +367,14 @@ struct vmcb_save_area {u64 br_to;u64 last_excp_from;u64 last_excp_to; - -/* -* The following part of the save area is valid only for -* SEV-ES guests when referenced through the GHCB or for -* saving to the host save area. -*/ -u8 reserved_7[72 ]; -u32 spec_ctrl;/* Guest version of SPEC_CTRL at 0x2E0 */ -u8 reserved_7b[4 ]; +u8 reserved_7[80 ];u32 pkru; -u8 reserved_7a[20 ]; -u64 reserved_8;/* rax already available at 0x01f8 */ +u8 reserved_9[20 ]; +u64 reserved_10;/* rax already available at 0x01f8 */ u64 rcx;u64 rdx;u64 rbx; -u64 reserved_9;/* rsp already available at 0x01d8 */ +u64 reserved_11;/* rsp already available at 0x01d8 */ u64 rbp;u64 rsi;u64 rdi;
@@ -343,23 +386,25 @@ struct vmcb_save_area {u64 r13;u64 r14;u64 r15; -u8 reserved_10[16 ]; +u8 reserved_12[16 ];u64 sw_exit_code;u64 sw_exit_info_1;u64 sw_exit_info_2;u64 sw_scratch;u64 sev_features; -u8 reserved_11[48 ]; +u8 reserved_13[48 ];u64 xcr0;u8 valid_bitmap[16 ];u64 x87_state_gpa; } __packed; +#define GHCB_SHARED_BUF_SIZE 2032 +struct ghcb { -struct vmcb_save_area save; -u8 reserved_save[2048 -sizeof (struct vmcb_save_area )]; +struct sev_es_save_area save; +u8 reserved_save[2048 -sizeof (struct sev_es_save_area )]; -u8 shared_buffer[2032 ]; +u8 shared_buffer[GHCB_SHARED_BUF_SIZE ];u8 reserved_1[10 ];u16 protocol_version;/* negotiated SEV-ES/GHCB protocol version */
@@ -367,13 +412,15 @@ struct ghcb { } __packed; -#define EXPECTED_VMCB_SAVE_AREA_SIZE 1032 +#define EXPECTED_VMCB_SAVE_AREA_SIZE 740 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZEstatic inline void __unused_size_checks (void ) {BUILD_BUG_ON (sizeof (struct vmcb_save_area ) !=EXPECTED_VMCB_SAVE_AREA_SIZE ); +BUILD_BUG_ON (sizeof (struct sev_es_save_area ) !=EXPECTED_SEV_ES_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct vmcb_control_area ) !=EXPECTED_VMCB_CONTROL_AREA_SIZE );BUILD_BUG_ON (sizeof (struct ghcb ) !=EXPECTED_GHCB_SIZE ); }
@@ -443,7 +490,7 @@ struct vmcb {/* GHCB Accessor functions */ #define GHCB_BITMAP_IDX (field) \ - (offsetof(struct vmcb_save_area, field) / sizeof(u64)) + (offsetof(struct sev_es_save_area, field) / sizeof(u64))#define DEFINE_GHCB_ACCESSORS (field) \ static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb) \
arch/x86/kvm/svm/sev.c +11 -11
@@ -559,12 +559,20 @@ e_unpin:static int sev_es_sync_vmsa (struct vcpu_svm *svm) { -struct vmcb_save_area *save = &svm->vmcb->save; +struct sev_es_save_area *save = svm->sev_es.vmsa;/* Check some debug related fields before encrypting the VMSA */ -if (svm->vcpu.guest_debug || (save->dr7 & ~DR7_FIXED_1 )) +if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1 ))return -EINVAL ; +/* +* SEV-ES will use a VMSA that is pointed to by the VMCB, not +* the traditional VMSA that is part of the VMCB. Copy the +* traditional VMSA as it has been built so far (in prep +* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. +*/ +memcpy (save, &svm->vmcb->save,sizeof (svm->vmcb->save)); +/* Sync registgers */ save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX ]; save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX ];
@@ -592,14 +600,6 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->xss = svm->vcpu.arch.ia32_xss; save->dr6 = svm->vcpu.arch.dr6; -/* -* SEV-ES will use a VMSA that is pointed to by the VMCB, not -* the traditional VMSA that is part of the VMCB. Copy the -* traditional VMSA as it has been built so far (in prep -* for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. -*/ -memcpy (svm->sev_es.vmsa, save,sizeof (*save)); -return 0 ; }
@@ -2932,7 +2932,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm) sev_enc_bit)); } -void sev_es_prepare_switch_to_guest (struct vmcb_save_area *hostsa) +void sev_es_prepare_switch_to_guest (struct sev_es_save_area *hostsa) {/* * As an SEV-ES guest, hardware will restore the host state on VMEXIT,
arch/x86/kvm/svm/svm.c +2 -2
@@ -1270,8 +1270,8 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)*/ vmsave (__sme_page_pa (sd->save_area));if (sev_es_guest (vcpu->kvm)) { -struct vmcb_save_area *hostsa; - hostsa = (struct vmcb_save_area *)(page_address (sd->save_area) +0x400 ); +struct sev_es_save_area *hostsa; + hostsa = (struct sev_es_save_area *)(page_address (sd->save_area) +0x400 );sev_es_prepare_switch_to_guest (hostsa); }
arch/x86/kvm/svm/svm.h +2 -2
@@ -181,7 +181,7 @@ struct svm_nested_state {struct vcpu_sev_es_state {/* SEV-ES support */ -struct vmcb_save_area *vmsa; +struct sev_es_save_area *vmsa;struct ghcb *ghcb;struct kvm_host_map ghcb_map;bool received_first_sipi;
@@ -620,7 +620,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);void sev_es_init_vmcb (struct vcpu_svm *svm);void sev_es_vcpu_reset (struct vcpu_svm *svm);void sev_vcpu_deliver_sipi_vector (struct kvm_vcpu *vcpu,u8 vector); -void sev_es_prepare_switch_to_guest (struct vmcb_save_area *hostsa); +void sev_es_prepare_switch_to_guest (struct sev_es_save_area *hostsa);void sev_es_unmap_ghcb (struct vcpu_svm *svm);/* vmenter.S */
PATCH v12 3/46 KVM: SVM: Create a separate mapping for the GHCB save area
In reply to Brijesh SinghFrom: Tom Lendacky <[email protected]>
The initial implementation of the GHCB spec was based on trying to keep the register state offsets the same relative to the VM save area. However, the save area for SEV-ES has changed within the hardware causing the relation between the SEV-ES save area to change relative to the GHCB save area.
This is the second step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create a GHCB save area that matches the GHCB specification.
--- arch/x86/include/asm/svm.h | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)
arch/x86/include/asm/svm.h +45 -3
@@ -390,11 +390,51 @@ struct sev_es_save_area {u64 x87_state_gpa; } __packed; +struct ghcb_save_area { +u8 reserved_1[203 ]; +u8 cpl; +u8 reserved_2[116 ]; +u64 xss; +u8 reserved_3[24 ]; +u64 dr7; +u8 reserved_4[16 ]; +u64 rip; +u8 reserved_5[88 ]; +u64 rsp; +u8 reserved_6[24 ]; +u64 rax; +u8 reserved_7[264 ]; +u64 rcx; +u64 rdx; +u64 rbx; +u8 reserved_8[8 ]; +u64 rbp; +u64 rsi; +u64 rdi; +u64 r8; +u64 r9; +u64 r10; +u64 r11; +u64 r12; +u64 r13; +u64 r14; +u64 r15; +u8 reserved_9[16 ]; +u64 sw_exit_code; +u64 sw_exit_info_1; +u64 sw_exit_info_2; +u64 sw_scratch; +u8 reserved_10[56 ]; +u64 xcr0; +u8 valid_bitmap[16 ]; +u64 x87_state_gpa; +} __packed; +#define GHCB_SHARED_BUF_SIZE 2032struct ghcb { -struct sev_es_save_area save; -u8 reserved_save[2048 -sizeof (struct sev_es_save_area )]; +struct ghcb_save_area save; +u8 reserved_save[2048 -sizeof (struct ghcb_save_area )];u8 shared_buffer[GHCB_SHARED_BUF_SIZE ];
@@ -405,6 +445,7 @@ struct ghcb {#define EXPECTED_VMCB_SAVE_AREA_SIZE 740 +#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZE
@@ -412,6 +453,7 @@ struct ghcb {static inline void __unused_size_checks (void ) {BUILD_BUG_ON (sizeof (struct vmcb_save_area ) !=EXPECTED_VMCB_SAVE_AREA_SIZE ); +BUILD_BUG_ON (sizeof (struct ghcb_save_area ) !=EXPECTED_GHCB_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct sev_es_save_area ) !=EXPECTED_SEV_ES_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct vmcb_control_area ) !=EXPECTED_VMCB_CONTROL_AREA_SIZE );BUILD_BUG_ON (sizeof (struct ghcb ) !=EXPECTED_GHCB_SIZE );
@@ -482,7 +524,7 @@ struct vmcb {/* GHCB Accessor functions */ #define GHCB_BITMAP_IDX (field) \ - (offsetof(struct sev_es_save_area, field) / sizeof(u64)) + (offsetof(struct ghcb_save_area, field) / sizeof(u64))#define DEFINE_GHCB_ACCESSORS (field) \ static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb) \
Signature · 1 line
2.25.1
[tip: x86/sev] KVM: SVM: Create a separate mapping for the GHCB save area
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: a4690359eaec985a1351786da887df1ba92440a0 Gitweb: https://git.kernel.org/tip/a4690359eaec985a1351786da887df1ba92440a0 Author: Tom Lendacky <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:13 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 12:13:34 +02:00
KVM: SVM: Create a separate mapping for the GHCB save area
The initial implementation of the GHCB spec was based on trying to keep the register state offsets the same relative to the VM save area. However, the save area for SEV-ES has changed within the hardware causing the relation between the SEV-ES save area to change relative to the GHCB save area.
This is the second step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Create a GHCB save area that matches the GHCB specification.
--- arch/x86/include/asm/svm.h | 48 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)
arch/x86/include/asm/svm.h +45 -3
@@ -398,11 +398,51 @@ struct sev_es_save_area {u64 x87_state_gpa; } __packed; +struct ghcb_save_area { +u8 reserved_1[203 ]; +u8 cpl; +u8 reserved_2[116 ]; +u64 xss; +u8 reserved_3[24 ]; +u64 dr7; +u8 reserved_4[16 ]; +u64 rip; +u8 reserved_5[88 ]; +u64 rsp; +u8 reserved_6[24 ]; +u64 rax; +u8 reserved_7[264 ]; +u64 rcx; +u64 rdx; +u64 rbx; +u8 reserved_8[8 ]; +u64 rbp; +u64 rsi; +u64 rdi; +u64 r8; +u64 r9; +u64 r10; +u64 r11; +u64 r12; +u64 r13; +u64 r14; +u64 r15; +u8 reserved_9[16 ]; +u64 sw_exit_code; +u64 sw_exit_info_1; +u64 sw_exit_info_2; +u64 sw_scratch; +u8 reserved_10[56 ]; +u64 xcr0; +u8 valid_bitmap[16 ]; +u64 x87_state_gpa; +} __packed; +#define GHCB_SHARED_BUF_SIZE 2032struct ghcb { -struct sev_es_save_area save; -u8 reserved_save[2048 -sizeof (struct sev_es_save_area )]; +struct ghcb_save_area save; +u8 reserved_save[2048 -sizeof (struct ghcb_save_area )];u8 shared_buffer[GHCB_SHARED_BUF_SIZE ];
@@ -413,6 +453,7 @@ struct ghcb {#define EXPECTED_VMCB_SAVE_AREA_SIZE 740 +#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZE
@@ -420,6 +461,7 @@ struct ghcb {static inline void __unused_size_checks (void ) {BUILD_BUG_ON (sizeof (struct vmcb_save_area ) !=EXPECTED_VMCB_SAVE_AREA_SIZE ); +BUILD_BUG_ON (sizeof (struct ghcb_save_area ) !=EXPECTED_GHCB_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct sev_es_save_area ) !=EXPECTED_SEV_ES_SAVE_AREA_SIZE );BUILD_BUG_ON (sizeof (struct vmcb_control_area ) !=EXPECTED_VMCB_CONTROL_AREA_SIZE );BUILD_BUG_ON (sizeof (struct ghcb ) !=EXPECTED_GHCB_SIZE );
@@ -490,7 +532,7 @@ struct vmcb {/* GHCB Accessor functions */ #define GHCB_BITMAP_IDX (field) \ - (offsetof(struct sev_es_save_area, field) / sizeof(u64)) + (offsetof(struct ghcb_save_area, field) / sizeof(u64))#define DEFINE_GHCB_ACCESSORS (field) \ static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb) \
PATCH v12 4/46 KVM: SVM: Update the SEV-ES save area mapping
In reply to Brijesh SinghFrom: Tom Lendacky <[email protected]>
This is the final step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Update the SEV-ES/SEV-SNP save area to match the APM. This save area will be used for the upcoming SEV-SNP AP Creation NAE event support.
--- arch/x86/include/asm/svm.h | 66 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-)
arch/x86/include/asm/svm.h +50 -16
@@ -326,7 +326,13 @@ struct sev_es_save_area {struct vmcb_seg ldtr;struct vmcb_seg idtr;struct vmcb_seg tr; -u8 reserved_1[43 ]; +u64 vmpl0_ssp; +u64 vmpl1_ssp; +u64 vmpl2_ssp; +u64 vmpl3_ssp; +u64 u_cet; +u8 reserved_1[2 ]; +u8 vmpl;u8 cpl;u8 reserved_2[4 ];u64 efer;
@@ -339,9 +345,19 @@ struct sev_es_save_area {u64 dr6;u64 rflags;u64 rip; -u8 reserved_4[88 ]; +u64 dr0; +u64 dr1; +u64 dr2; +u64 dr3; +u64 dr0_addr_mask; +u64 dr1_addr_mask; +u64 dr2_addr_mask; +u64 dr3_addr_mask; +u8 reserved_4[24 ];u64 rsp; -u8 reserved_5[24 ]; +u64 s_cet; +u64 ssp; +u64 isst_addr;u64 rax;u64 star;u64 lstar;
@@ -352,7 +368,7 @@ struct sev_es_save_area {u64 sysenter_esp;u64 sysenter_eip;u64 cr2; -u8 reserved_6[32 ]; +u8 reserved_5[32 ];u64 g_pat;u64 dbgctl;u64 br_from;
@@ -361,12 +377,12 @@ struct sev_es_save_area {u64 last_excp_to;u8 reserved_7[80 ];u32 pkru; -u8 reserved_9[20 ]; -u64 reserved_10;/* rax already available at 0x01f8 */ +u8 reserved_8[20 ]; +u64 reserved_9;/* rax already available at 0x01f8 */ u64 rcx;u64 rdx;u64 rbx; -u64 reserved_11;/* rsp already available at 0x01d8 */ +u64 reserved_10;/* rsp already available at 0x01d8 */ u64 rbp;u64 rsi;u64 rdi;
@@ -378,16 +394,34 @@ struct sev_es_save_area {u64 r13;u64 r14;u64 r15; -u8 reserved_12[16 ]; -u64 sw_exit_code; -u64 sw_exit_info_1; -u64 sw_exit_info_2; -u64 sw_scratch; +u8 reserved_11[16 ]; +u64 guest_exit_info_1; +u64 guest_exit_info_2; +u64 guest_exit_int_info; +u64 guest_nrip;u64 sev_features; -u8 reserved_13[48 ]; +u64 vintr_ctrl; +u64 guest_exit_code; +u64 virtual_tom; +u64 tlb_id; +u64 pcpu_id; +u64 event_inj;u64 xcr0; -u8 valid_bitmap[16 ]; -u64 x87_state_gpa; +u8 reserved_12[16 ]; + +/* Floating point area */ +u64 x87_dp; +u32 mxcsr; +u16 x87_ftw; +u16 x87_fsw; +u16 x87_fcw; +u16 x87_fop; +u16 x87_ds; +u16 x87_cs; +u64 x87_rip; +u8 fpreg_x87[80 ]; +u8 fpreg_xmm[256 ]; +u8 fpreg_ymm[256 ]; } __packed;struct ghcb_save_area {
@@ -446,7 +480,7 @@ struct ghcb {#define EXPECTED_VMCB_SAVE_AREA_SIZE 740#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032 -#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZE
Signature · 1 line
2.25.1
[tip: x86/sev] KVM: SVM: Update the SEV-ES save area mapping
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 6d3b3d34e39eb4ee9a7dbe7e28e2588e160f9c0f Gitweb: https://git.kernel.org/tip/6d3b3d34e39eb4ee9a7dbe7e28e2588e160f9c0f Author: Tom Lendacky <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:14 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 12:19:51 +02:00
KVM: SVM: Update the SEV-ES save area mapping
This is the final step in defining the multiple save areas to keep them separate and ensuring proper operation amongst the different types of guests. Update the SEV-ES/SEV-SNP save area to match the APM. This save area will be used for the upcoming SEV-SNP AP Creation NAE event support.
--- arch/x86/include/asm/svm.h | 66 ++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-)
arch/x86/include/asm/svm.h +50 -16
@@ -334,7 +334,13 @@ struct sev_es_save_area {struct vmcb_seg ldtr;struct vmcb_seg idtr;struct vmcb_seg tr; -u8 reserved_1[43 ]; +u64 vmpl0_ssp; +u64 vmpl1_ssp; +u64 vmpl2_ssp; +u64 vmpl3_ssp; +u64 u_cet; +u8 reserved_1[2 ]; +u8 vmpl;u8 cpl;u8 reserved_2[4 ];u64 efer;
@@ -347,9 +353,19 @@ struct sev_es_save_area {u64 dr6;u64 rflags;u64 rip; -u8 reserved_4[88 ]; +u64 dr0; +u64 dr1; +u64 dr2; +u64 dr3; +u64 dr0_addr_mask; +u64 dr1_addr_mask; +u64 dr2_addr_mask; +u64 dr3_addr_mask; +u8 reserved_4[24 ];u64 rsp; -u8 reserved_5[24 ]; +u64 s_cet; +u64 ssp; +u64 isst_addr;u64 rax;u64 star;u64 lstar;
@@ -360,7 +376,7 @@ struct sev_es_save_area {u64 sysenter_esp;u64 sysenter_eip;u64 cr2; -u8 reserved_6[32 ]; +u8 reserved_5[32 ];u64 g_pat;u64 dbgctl;u64 br_from;
@@ -369,12 +385,12 @@ struct sev_es_save_area {u64 last_excp_to;u8 reserved_7[80 ];u32 pkru; -u8 reserved_9[20 ]; -u64 reserved_10;/* rax already available at 0x01f8 */ +u8 reserved_8[20 ]; +u64 reserved_9;/* rax already available at 0x01f8 */ u64 rcx;u64 rdx;u64 rbx; -u64 reserved_11;/* rsp already available at 0x01d8 */ +u64 reserved_10;/* rsp already available at 0x01d8 */ u64 rbp;u64 rsi;u64 rdi;
@@ -386,16 +402,34 @@ struct sev_es_save_area {u64 r13;u64 r14;u64 r15; -u8 reserved_12[16 ]; -u64 sw_exit_code; -u64 sw_exit_info_1; -u64 sw_exit_info_2; -u64 sw_scratch; +u8 reserved_11[16 ]; +u64 guest_exit_info_1; +u64 guest_exit_info_2; +u64 guest_exit_int_info; +u64 guest_nrip;u64 sev_features; -u8 reserved_13[48 ]; +u64 vintr_ctrl; +u64 guest_exit_code; +u64 virtual_tom; +u64 tlb_id; +u64 pcpu_id; +u64 event_inj;u64 xcr0; -u8 valid_bitmap[16 ]; -u64 x87_state_gpa; +u8 reserved_12[16 ]; + +/* Floating point area */ +u64 x87_dp; +u32 mxcsr; +u16 x87_ftw; +u16 x87_fsw; +u16 x87_fcw; +u16 x87_fop; +u16 x87_ds; +u16 x87_cs; +u64 x87_rip; +u8 fpreg_x87[80 ]; +u8 fpreg_xmm[256 ]; +u8 fpreg_ymm[256 ]; } __packed;struct ghcb_save_area {
@@ -454,7 +488,7 @@ struct ghcb {#define EXPECTED_VMCB_SAVE_AREA_SIZE 740#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032 -#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1032 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZE
PATCH v12 5/46 x86/boot: Introduce helpers for MSR reads/writes
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
The current set of helpers used throughout the run-time kernel have dependencies on code/facilities outside of the boot kernel, so there are a number of call-sites throughout the boot kernel where inline assembly is used instead. More will be added with subsequent patches that add support for SEV-SNP, so take the opportunity to provide a basic set of helpers that can be used by the boot kernel to reduce reliance on inline assembly.
Use boot_* prefix so that it's clear these are helpers specific to the boot kernel to avoid any confusion with the various other MSR read/write helpers.
--- arch/x86/boot/msr.h | 28 ++++++++++++++++++++++++++++ arch/x86/include/asm/msr.h | 11 +---------- arch/x86/include/asm/shared/msr.h | 15 +++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 arch/x86/boot/msr.h create mode 100644 arch/x86/include/asm/shared/msr.h
arch/x86/boot/msr.h new file +28 -0
@@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Helpers/definitions related to MSR access. +*/ + +#ifndef BOOT_MSR_H +#define BOOT_MSR_H + +#include <asm/shared/msr.h> + +/* +* The kernel proper already defines rdmsr()/wrmsr(), but they are not for the +* boot kernel since they rely tracepoint/exception handling infrastructure +* that's not available here, hence these boot_{rd,wr}msr helpers which serve +* the singular purpose of wrapping the RDMSR/WRMSR instructions to reduce the +* need for inline assembly calls throughout the boot kernel code. +*/ +static inline void boot_rdmsr (unsigned int msr,struct msr *m) +{ + asmvolatile ("rdmsr" :"=a" (m->l),"=d" (m->h) :"c" (msr)); +} + +static inline void boot_wrmsr (unsigned int msr,const struct msr *m) +{ + asmvolatile ("wrmsr" : :"c" (msr),"a" (m->l),"d" (m->h) :"memory" ); +} + +#endif /* BOOT_MSR_H */
arch/x86/include/asm/msr.h +1 -10
@@ -10,16 +10,7 @@#include <asm/errno.h> #include <asm/cpumask.h> #include <uapi/asm/msr.h> - -struct msr { -union { -struct { -u32 l; -u32 h; - }; -u64 q; - }; -}; +#include <asm/shared/msr.h> struct msr_info {u32 msr_no;
arch/x86/include/asm/shared/msr.h new file +15 -0
@@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_SHARED_MSR_H +#define _ASM_X86_SHARED_MSR_H + +struct msr { +union { +struct { +u32 l; +u32 h; + }; +u64 q; + }; +}; + +#endif /* _ASM_X86_SHARED_MSR_H */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/boot: Introduce helpers for MSR reads/writes
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 176db622573f028f85221873ea4577e096785315 Gitweb: https://git.kernel.org/tip/176db622573f028f85221873ea4577e096785315 Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:09:59 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 12:59:17 +02:00
x86/boot: Introduce helpers for MSR reads/writes
The current set of helpers used throughout the run-time kernel have dependencies on code/facilities outside of the boot kernel, so there are a number of call-sites throughout the boot kernel where inline assembly is used instead. More will be added with subsequent patches that add support for SEV-SNP, so take the opportunity to provide a basic set of helpers that can be used by the boot kernel to reduce reliance on inline assembly.
Use boot_* prefix so that it's clear these are helpers specific to the boot kernel to avoid any confusion with the various other MSR read/write helpers.
[ bp: Disambiguate parameter names and trim comment. ]
--- arch/x86/boot/msr.h | 26 ++++++++++++++++++++++++++ arch/x86/include/asm/msr.h | 11 +---------- arch/x86/include/asm/shared/msr.h | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 arch/x86/boot/msr.h create mode 100644 arch/x86/include/asm/shared/msr.h
arch/x86/boot/msr.h new file +26 -0
@@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Helpers/definitions related to MSR access. +*/ + +#ifndef BOOT_MSR_H +#define BOOT_MSR_H + +#include <asm/shared/msr.h> + +/* +* The kernel proper already defines rdmsr()/wrmsr(), but they are not for the +* boot kernel since they rely on tracepoint/exception handling infrastructure +* that's not available here. +*/ +static inline void boot_rdmsr (unsigned int reg,struct msr *m) +{ + asmvolatile ("rdmsr" :"=a" (m->l),"=d" (m->h) :"c" (reg)); +} + +static inline void boot_wrmsr (unsigned int reg,const struct msr *m) +{ + asmvolatile ("wrmsr" : :"c" (reg),"a" (m->l),"d" (m->h) :"memory" ); +} + +#endif /* BOOT_MSR_H */
arch/x86/include/asm/msr.h +1 -10
@@ -10,16 +10,7 @@#include <asm/errno.h> #include <asm/cpumask.h> #include <uapi/asm/msr.h> - -struct msr { -union { -struct { -u32 l; -u32 h; - }; -u64 q; - }; -}; +#include <asm/shared/msr.h> struct msr_info {u32 msr_no;
arch/x86/include/asm/shared/msr.h new file +15 -0
@@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_SHARED_MSR_H +#define _ASM_X86_SHARED_MSR_H + +struct msr { +union { +struct { +u32 l; +u32 h; + }; +u64 q; + }; +}; + +#endif /* _ASM_X86_SHARED_MSR_H */
PATCH v12 6/46 x86/boot: Use MSR read/write helpers instead of inline assembly
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Update all C code to use the new boot_rdmsr()/boot_wrmsr() helpers instead of relying on inline assembly.
--- arch/x86/boot/compressed/sev.c | 17 +++++++---------- arch/x86/boot/cpucheck.c | 30 +++++++++++++++--------------- 2 files changed, 22 insertions(+), 25 deletions(-)
arch/x86/boot/compressed/sev.c +7 -10
@@ -22,6 +22,7 @@#include <asm/svm.h> #include "error.h" +#include "../msr.h" struct ghcb boot_ghcb_page__aligned(PAGE_SIZE) ;struct ghcb *boot_ghcb;
@@ -56,23 +57,19 @@ static unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)static inline u64 sev_es_rd_ghcb_msr (void ) { -unsigned long low, high; +struct msr m; - asmvolatile ("rdmsr" :"=a" (low),"=d" (high) : -"c" (MSR_AMD64_SEV_ES_GHCB )); +boot_rdmsr (MSR_AMD64_SEV_ES_GHCB , &m); -return ((high <<32 ) | low); +return m.q; }static inline void sev_es_wr_ghcb_msr (u64 val) { -u32 low, high; +struct msr m; - low = val &0xffffffffUL ; - high = val >>32 ; - - asmvolatile ("wrmsr" : :"c" (MSR_AMD64_SEV_ES_GHCB ), -"a" (low),"d" (high) :"memory" ); + m.q = val; +boot_wrmsr (MSR_AMD64_SEV_ES_GHCB , &m); }static enum es_result vc_decode_insn (struct es_em_ctxt *ctxt)
arch/x86/boot/cpucheck.c +15 -15
@@ -27,6 +27,7 @@#include <asm/required-features.h> #include <asm/msr-index.h> #include "string.h" +#include "msr.h" static u32 err_flags[NCAPINTS ];
@@ -130,12 +131,11 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)/* If this is an AMD and we're only missing SSE+SSE2, try to turn them on */ -u32 ecx =MSR_K7_HWCR ; -u32 eax, edx; +struct msr m; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - eax &= ~(1 <<15 ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_rdmsr (MSR_K7_HWCR , &m); + m.l &= ~(1 <<15 ); +boot_wrmsr (MSR_K7_HWCR , &m);get_cpuflags ();/* Make sure it really did something */ err =check_cpuflags ();
@@ -145,28 +145,28 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)/* If this is a VIA C3, we might have to enable CX8 explicitly */ -u32 ecx =MSR_VIA_FCR ; -u32 eax, edx; +struct msr m; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - eax |= (1 <<1 )|(1 <<7 ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_rdmsr (MSR_VIA_FCR , &m); + m.l |= (1 <<1 ) | (1 <<7 ); +boot_wrmsr (MSR_VIA_FCR , &m);set_bit (X86_FEATURE_CX8 , cpu.flags); err =check_cpuflags (); }else if (err ==0x01 &&is_transmeta ()) {/* Transmeta might have masked feature bits in word 0 */ -u32 ecx =0x80860004 ; -u32 eax, edx; +struct msr m, m_tmp;u32 level =1 ; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - asm("wrmsr" : :"a" (~0 ),"d" (edx),"c" (ecx)); +boot_rdmsr (0x80860004 , &m); + m_tmp = m; + m_tmp.l = ~0 ; +boot_wrmsr (0x80860004 , &m_tmp); asm("cpuid" :"+a" (level),"=d" (cpu.flags[0 ]) : :"ecx" ,"ebx" ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_wrmsr (0x80860004 , &m); err =check_cpuflags (); } else if (err == 0x01 &&
Signature · 1 line
2.25.1
[tip: x86/sev] x86/boot: Use MSR read/write helpers instead of inline assembly
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 950d00558a920227b5703d1fcc4751cfe03853cd Gitweb: https://git.kernel.org/tip/950d00558a920227b5703d1fcc4751cfe03853cd Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:00 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:02:13 +02:00
x86/boot: Use MSR read/write helpers instead of inline assembly
Update all C code to use the new boot_rdmsr()/boot_wrmsr() helpers instead of relying on inline assembly.
--- arch/x86/boot/compressed/sev.c | 17 +++++++---------- arch/x86/boot/cpucheck.c | 30 +++++++++++++++--------------- 2 files changed, 22 insertions(+), 25 deletions(-)
arch/x86/boot/compressed/sev.c +7 -10
@@ -22,6 +22,7 @@#include <asm/svm.h> #include "error.h" +#include "../msr.h" struct ghcb boot_ghcb_page__aligned(PAGE_SIZE) ;struct ghcb *boot_ghcb;
@@ -56,23 +57,19 @@ static unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)static inline u64 sev_es_rd_ghcb_msr (void ) { -unsigned long low, high; +struct msr m; - asmvolatile ("rdmsr" :"=a" (low),"=d" (high) : -"c" (MSR_AMD64_SEV_ES_GHCB )); +boot_rdmsr (MSR_AMD64_SEV_ES_GHCB , &m); -return ((high <<32 ) | low); +return m.q; }static inline void sev_es_wr_ghcb_msr (u64 val) { -u32 low, high; +struct msr m; - low = val &0xffffffffUL ; - high = val >>32 ; - - asmvolatile ("wrmsr" : :"c" (MSR_AMD64_SEV_ES_GHCB ), -"a" (low),"d" (high) :"memory" ); + m.q = val; +boot_wrmsr (MSR_AMD64_SEV_ES_GHCB , &m); }static enum es_result vc_decode_insn (struct es_em_ctxt *ctxt)
arch/x86/boot/cpucheck.c +15 -15
@@ -27,6 +27,7 @@#include <asm/required-features.h> #include <asm/msr-index.h> #include "string.h" +#include "msr.h" static u32 err_flags[NCAPINTS ];
@@ -130,12 +131,11 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)/* If this is an AMD and we're only missing SSE+SSE2, try to turn them on */ -u32 ecx =MSR_K7_HWCR ; -u32 eax, edx; +struct msr m; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - eax &= ~(1 <<15 ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_rdmsr (MSR_K7_HWCR , &m); + m.l &= ~(1 <<15 ); +boot_wrmsr (MSR_K7_HWCR , &m);get_cpuflags ();/* Make sure it really did something */ err =check_cpuflags ();
@@ -145,28 +145,28 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)/* If this is a VIA C3, we might have to enable CX8 explicitly */ -u32 ecx =MSR_VIA_FCR ; -u32 eax, edx; +struct msr m; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - eax |= (1 <<1 )|(1 <<7 ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_rdmsr (MSR_VIA_FCR , &m); + m.l |= (1 <<1 ) | (1 <<7 ); +boot_wrmsr (MSR_VIA_FCR , &m);set_bit (X86_FEATURE_CX8 , cpu.flags); err =check_cpuflags (); }else if (err ==0x01 &&is_transmeta ()) {/* Transmeta might have masked feature bits in word 0 */ -u32 ecx =0x80860004 ; -u32 eax, edx; +struct msr m, m_tmp;u32 level =1 ; - asm("rdmsr" :"=a" (eax),"=d" (edx) :"c" (ecx)); - asm("wrmsr" : :"a" (~0 ),"d" (edx),"c" (ecx)); +boot_rdmsr (0x80860004 , &m); + m_tmp = m; + m_tmp.l = ~0 ; +boot_wrmsr (0x80860004 , &m_tmp); asm("cpuid" :"+a" (level),"=d" (cpu.flags[0 ]) : :"ecx" ,"ebx" ); - asm("wrmsr" : :"a" (eax),"d" (edx),"c" (ecx)); +boot_wrmsr (0x80860004 , &m); err =check_cpuflags (); } else if (err == 0x01 &&
PATCH v12 7/46 x86/compressed/64: Detect/setup SEV/SME features earlier in boot
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
With upcoming SEV-SNP support, SEV-related features need to be initialized earlier in boot, at the same point the initial #VC handler is set up, so that the SEV-SNP CPUID table can be utilized during the initial feature checks. Also, SEV-SNP feature detection will rely on EFI helper functions to scan the EFI config table for the Confidential Computing blob, and so would need to be implemented at least partially in C.
Currently set_sev_encryption_mask() is used to initialize the sev_status and sme_me_mask globals that advertise what SEV/SME features are available in a guest. Rename it to sev_enable() to better reflect that (SME is only enabled in the case of SEV guests in the boot/compressed kernel), and move it to just after the stage1 #VC handler is set up so that it can be used to initialize SEV-SNP as well in future patches.
While at it, re-implement it as C code so that all SEV feature detection can be better consolidated with upcoming SEV-SNP feature detection, which will also be in C.
The 32-bit entry path remains unchanged, as it never relied on the set_sev_encryption_mask() initialization to begin with, possibly due to the normal rva() helper for accessing globals only being usable by code in .head.text. Either way, 32-bit entry for SEV-SNP would likely only be supported for non-EFI boot paths, and so wouldn't rely on existing EFI helper functions, and so could be handled by a separate/simpler 32-bit initializer in the future if needed.
--- arch/x86/boot/compressed/head_64.S | 37 +++++++++++++++----------- arch/x86/boot/compressed/mem_encrypt.S | 36 ------------------------- arch/x86/boot/compressed/misc.h | 4 +-- arch/x86/boot/compressed/sev.c | 36 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 53 deletions(-)
arch/x86/boot/compressed/head_64.S +22 -15
@@ -189,11 +189,11 @@ SYM_FUNC_START(startup_32) subl $32, %eax /* Encryption bit is always above bit 31 */ bts %eax, %edx /* Set encryption mask for page tables */ /* - * Mark SEV as active in sev_status so that startup32_check_sev_cbit() - * will do a check. The sev_status memory will be fully initialized - * with the contents of MSR_AMD_SEV_STATUS later in - * set_sev_encryption_mask(). For now it is sufficient to know that SEV - * is active. + * Set MSR_AMD64_SEV_ENABLED_BIT in sev_status so that + * startup32_check_sev_cbit() will do a check. sev_enable() will + * initialize sev_status with all the bits reported by + * MSR_AMD_SEV_STATUS later, but only MSR_AMD64_SEV_ENABLED_BIT + * needs to be set for now. */ movl $1, rva(sev_status)(%ebp) 1:
@@ -447,6 +447,23 @@ SYM_CODE_START(startup_64) call load_stage1_idt popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* + * Now that the stage1 interrupt handlers are set up, #VC exceptions from + * CPUID instructions can be properly handled for SEV-ES guests. + * + * For SEV-SNP, the CPUID table also needs to be set up in advance of any + * CPUID instructions being issued, so go ahead and do that now via + * sev_enable(), which will also handle the rest of the SEV-related + * detection/setup to ensure that has been done in advance of any dependent + * code. + */ + pushq %rsi + movq %rsi, %rdi /* real mode address */ + call sev_enable + popq %rsi +#endif + /* * paging_prepare() sets up the trampoline and checks if we need to * enable 5-level paging.
@@ -559,17 +576,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) shrq $3, %rcx rep stosq -/* - * If running as an SEV guest, the encryption mask is required in the - * page-table setup code below. When the guest also has SEV-ES enabled - * set_sev_encryption_mask() will cause #VC exceptions, but the stage2 - * handler can't map its GHCB because the page-table is not set up yet. - * So set up the encryption mask here while still on the stage1 #VC - * handler. Then load stage2 IDT and switch to the kernel's own - * page-table. - */ pushq %rsi - call set_sev_encryption_mask call load_stage2_idt /* Pass boot_params to initialize_identity_maps() */
arch/x86/boot/compressed/mem_encrypt.S +0 -36
@@ -187,42 +187,6 @@ SYM_CODE_END(startup32_vc_handler) .code64 #include "../../kernel/sev_verify_cbit.S" -SYM_FUNC_START(set_sev_encryption_mask) -#ifdef CONFIG_AMD_MEM_ENCRYPT - push %rbp - push %rdx - - movq %rsp, %rbp /* Save current stack pointer */ - - call get_sev_encryption_bit /* Get the encryption bit position */ - testl %eax, %eax - jz .Lno_sev_mask - - bts %rax, sme_me_mask(%rip) /* Create the encryption mask */ - - /* - * Read MSR_AMD64_SEV again and store it to sev_status. Can't do this in - * get_sev_encryption_bit() because this function is 32-bit code and - * shared between 64-bit and 32-bit boot path. - */ - movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */ - rdmsr - - /* Store MSR value in sev_status */ - shlq $32, %rdx - orq %rdx, %rax - movq %rax, sev_status(%rip) - -.Lno_sev_mask: - movq %rbp, %rsp /* Restore original stack pointer */ - - pop %rdx - pop %rbp -#endif - - xor %rax, %rax - RET -SYM_FUNC_END(set_sev_encryption_mask) .data
arch/x86/boot/compressed/misc.h +2 -2
@@ -120,12 +120,12 @@ static inline void console_init(void) { }#endif -void set_sev_encryption_mask (void ); -#ifdef CONFIG_AMD_MEM_ENCRYPT +void sev_enable (struct boot_params *bp);void sev_es_shutdown_ghcb (void );extern bool sev_es_check_ghcb_fault (unsigned long address);#else +static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }static inline bool sev_es_check_ghcb_fault (unsigned long address) {
arch/x86/boot/compressed/sev.c +36 -0
@@ -201,3 +201,39 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)else if (result !=ES_RETRY )sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); } + +void sev_enable (struct boot_params *bp) +{ +unsigned int eax, ebx, ecx, edx; +struct msr m; + +/* Check for the SME/SEV support leaf */ + eax =0x80000000 ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +if (eax <0x8000001f ) +return ; + +/* +* Check for the SME/SEV feature: +* CPUID Fn8000_001F[EAX] +* - Bit 0 - Secure Memory Encryption support +* - Bit 1 - Secure Encrypted Virtualization support +* CPUID Fn8000_001F[EBX] +* - Bits 5:0 - Pagetable bit position used to indicate encryption +*/ + eax =0x8000001f ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +/* Check whether SEV is supported */ +if (!(eax &BIT (1 ))) +return ; + +/* Set the SME mask if this is an SEV guest. */ +boot_rdmsr (MSR_AMD64_SEV , &m); + sev_status = m.q; +if (!(sev_status &MSR_AMD64_SEV_ENABLED )) +return ; + + sme_me_mask =BIT_ULL (ebx &0x3f ); +}
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/64: Detect/setup SEV/SME features earlier during boot
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: ec1c66af3a30d45c2420da0974c01d3515dba26e Gitweb: https://git.kernel.org/tip/ec1c66af3a30d45c2420da0974c01d3515dba26e Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:01 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:02:21 +02:00
x86/compressed/64: Detect/setup SEV/SME features earlier during boot
With upcoming SEV-SNP support, SEV-related features need to be initialized earlier during boot, at the same point the initial #VC handler is set up, so that the SEV-SNP CPUID table can be utilized during the initial feature checks. Also, SEV-SNP feature detection will rely on EFI helper functions to scan the EFI config table for the Confidential Computing blob, and so would need to be implemented at least partially in C.
Currently set_sev_encryption_mask() is used to initialize the sev_status and sme_me_mask globals that advertise what SEV/SME features are available in a guest. Rename it to sev_enable() to better reflect that (SME is only enabled in the case of SEV guests in the boot/compressed kernel), and move it to just after the stage1 #VC handler is set up so that it can be used to initialize SEV-SNP as well in future patches.
While at it, re-implement it as C code so that all SEV feature detection can be better consolidated with upcoming SEV-SNP feature detection, which will also be in C.
The 32-bit entry path remains unchanged, as it never relied on the set_sev_encryption_mask() initialization to begin with.
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/head_64.S | 37 ++++++++++++++----------- arch/x86/boot/compressed/mem_encrypt.S | 36 +------------------------ arch/x86/boot/compressed/misc.h | 4 +-- arch/x86/boot/compressed/sev.c | 36 ++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 53 deletions(-)
arch/x86/boot/compressed/head_64.S +22 -15
@@ -189,11 +189,11 @@ SYM_FUNC_START(startup_32) subl $32, %eax /* Encryption bit is always above bit 31 */ bts %eax, %edx /* Set encryption mask for page tables */ /* - * Mark SEV as active in sev_status so that startup32_check_sev_cbit() - * will do a check. The sev_status memory will be fully initialized - * with the contents of MSR_AMD_SEV_STATUS later in - * set_sev_encryption_mask(). For now it is sufficient to know that SEV - * is active. + * Set MSR_AMD64_SEV_ENABLED_BIT in sev_status so that + * startup32_check_sev_cbit() will do a check. sev_enable() will + * initialize sev_status with all the bits reported by + * MSR_AMD_SEV_STATUS later, but only MSR_AMD64_SEV_ENABLED_BIT + * needs to be set for now. */ movl $1, rva(sev_status)(%ebp) 1:
@@ -447,6 +447,23 @@ SYM_CODE_START(startup_64) call load_stage1_idt popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* + * Now that the stage1 interrupt handlers are set up, #VC exceptions from + * CPUID instructions can be properly handled for SEV-ES guests. + * + * For SEV-SNP, the CPUID table also needs to be set up in advance of any + * CPUID instructions being issued, so go ahead and do that now via + * sev_enable(), which will also handle the rest of the SEV-related + * detection/setup to ensure that has been done in advance of any dependent + * code. + */ + pushq %rsi + movq %rsi, %rdi /* real mode address */ + call sev_enable + popq %rsi +#endif + /* * paging_prepare() sets up the trampoline and checks if we need to * enable 5-level paging.
@@ -558,17 +575,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) shrq $3, %rcx rep stosq -/* - * If running as an SEV guest, the encryption mask is required in the - * page-table setup code below. When the guest also has SEV-ES enabled - * set_sev_encryption_mask() will cause #VC exceptions, but the stage2 - * handler can't map its GHCB because the page-table is not set up yet. - * So set up the encryption mask here while still on the stage1 #VC - * handler. Then load stage2 IDT and switch to the kernel's own - * page-table. - */ pushq %rsi - call set_sev_encryption_mask call load_stage2_idt /* Pass boot_params to initialize_identity_maps() */
arch/x86/boot/compressed/mem_encrypt.S +0 -36
@@ -187,42 +187,6 @@ SYM_CODE_END(startup32_vc_handler) .code64 #include "../../kernel/sev_verify_cbit.S" -SYM_FUNC_START(set_sev_encryption_mask) -#ifdef CONFIG_AMD_MEM_ENCRYPT - push %rbp - push %rdx - - movq %rsp, %rbp /* Save current stack pointer */ - - call get_sev_encryption_bit /* Get the encryption bit position */ - testl %eax, %eax - jz .Lno_sev_mask - - bts %rax, sme_me_mask(%rip) /* Create the encryption mask */ - - /* - * Read MSR_AMD64_SEV again and store it to sev_status. Can't do this in - * get_sev_encryption_bit() because this function is 32-bit code and - * shared between 64-bit and 32-bit boot path. - */ - movl $MSR_AMD64_SEV, %ecx /* Read the SEV MSR */ - rdmsr - - /* Store MSR value in sev_status */ - shlq $32, %rdx - orq %rdx, %rax - movq %rax, sev_status(%rip) - -.Lno_sev_mask: - movq %rbp, %rsp /* Restore original stack pointer */ - - pop %rdx - pop %rbp -#endif - - xor %rax, %rax - RET -SYM_FUNC_END(set_sev_encryption_mask) .data
arch/x86/boot/compressed/misc.h +2 -2
@@ -120,12 +120,12 @@ static inline void console_init(void) { }#endif -void set_sev_encryption_mask (void ); -#ifdef CONFIG_AMD_MEM_ENCRYPT +void sev_enable (struct boot_params *bp);void sev_es_shutdown_ghcb (void );extern bool sev_es_check_ghcb_fault (unsigned long address);#else +static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }static inline bool sev_es_check_ghcb_fault (unsigned long address) {
arch/x86/boot/compressed/sev.c +36 -0
@@ -201,3 +201,39 @@ finish:else if (result !=ES_RETRY )sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); } + +void sev_enable (struct boot_params *bp) +{ +unsigned int eax, ebx, ecx, edx; +struct msr m; + +/* Check for the SME/SEV support leaf */ + eax =0x80000000 ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +if (eax <0x8000001f ) +return ; + +/* +* Check for the SME/SEV feature: +* CPUID Fn8000_001F[EAX] +* - Bit 0 - Secure Memory Encryption support +* - Bit 1 - Secure Encrypted Virtualization support +* CPUID Fn8000_001F[EBX] +* - Bits 5:0 - Pagetable bit position used to indicate encryption +*/ + eax =0x8000001f ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +/* Check whether SEV is supported */ +if (!(eax &BIT (1 ))) +return ; + +/* Set the SME mask if this is an SEV guest. */ +boot_rdmsr (MSR_AMD64_SEV , &m); + sev_status = m.q; +if (!(sev_status &MSR_AMD64_SEV_ENABLED )) +return ; + + sme_me_mask =BIT_ULL (ebx &0x3f ); +}
PATCH v12 8/46 x86/sev: Detect/setup SEV/SME features earlier in boot
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
sme_enable() handles feature detection for both SEV and SME. Future patches will also use it for SEV-SNP feature detection/setup, which will need to be done immediately after the first #VC handler is set up. Move it now in preparation.
--- arch/x86/kernel/head64.c | 3 --- arch/x86/kernel/head_64.S | 13 +++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-)
arch/x86/kernel/head64.c +0 -3
@@ -192,9 +192,6 @@ unsigned long __head __startup_64(unsigned long physaddr,if (load_delta & ~PMD_PAGE_MASK )for (;;); -/* Activate Secure Memory Encryption (SME) if supported and enabled */ -sme_enable (bp); -/* Include the SME encryption mask in the fixup value */ load_delta +=sme_get_me_mask ();
arch/x86/kernel/head_64.S +13 -0
@@ -69,6 +69,19 @@ SYM_CODE_START_NOALIGN(startup_64) call startup_64_setup_env popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* + * Activate SEV/SME memory encryption if supported/enabled. This needs to + * be done now, since this also includes setup of the SEV-SNP CPUID table, + * which needs to be done before any CPUID instructions are executed in + * subsequent code. + */ + movq %rsi, %rdi + pushq %rsi + call sme_enable + popq %rsi +#endif + /* Now switch to __KERNEL_CS so IRET works reliably */ pushq $__KERNEL_CS leaq .Lon_kernel_cs(%rip), %rax
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Detect/setup SEV/SME features earlier in boot
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: bcce829083339bf862d66df602cbb111943da8fb Gitweb: https://git.kernel.org/tip/bcce829083339bf862d66df602cbb111943da8fb Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:02 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:02:26 +02:00
x86/sev: Detect/setup SEV/SME features earlier in boot
sme_enable() handles feature detection for both SEV and SME. Future patches will also use it for SEV-SNP feature detection/setup, which will need to be done immediately after the first #VC handler is set up. Move it now in preparation.
--- arch/x86/kernel/head64.c | 3 --- arch/x86/kernel/head_64.S | 13 +++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-)
arch/x86/kernel/head64.c +0 -3
@@ -192,9 +192,6 @@ unsigned long __head __startup_64(unsigned long physaddr,if (load_delta & ~PMD_PAGE_MASK )for (;;); -/* Activate Secure Memory Encryption (SME) if supported and enabled */ -sme_enable (bp); -/* Include the SME encryption mask in the fixup value */ load_delta +=sme_get_me_mask ();
arch/x86/kernel/head_64.S +13 -0
@@ -69,6 +69,19 @@ SYM_CODE_START_NOALIGN(startup_64) call startup_64_setup_env popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* + * Activate SEV/SME memory encryption if supported/enabled. This needs to + * be done now, since this also includes setup of the SEV-SNP CPUID table, + * which needs to be done before any CPUID instructions are executed in + * subsequent code. + */ + movq %rsi, %rdi + pushq %rsi + call sme_enable + popq %rsi +#endif + /* Now switch to __KERNEL_CS so IRET works reliably */ pushq $__KERNEL_CS leaq .Lon_kernel_cs(%rip), %rax
PATCH v12 9/46 x86/mm: Extend cc_attr to include AMD SEV-SNP
In reply to Brijesh SinghThe CC_ATTR_GUEST_SEV_SNP can be used by the guest to query whether the SNP (Secure Nested Paging) feature is active.
--- arch/x86/coco/core.c | 3 +++ arch/x86/include/asm/msr-index.h | 2 ++ arch/x86/mm/mem_encrypt.c | 4 ++++ include/linux/cc_platform.h | 8 ++++++++ 4 files changed, 17 insertions(+)
arch/x86/coco/core.c +3 -0
@@ -57,6 +57,9 @@ static bool amd_cc_platform_has(enum cc_attr attr)return (sev_status &MSR_AMD64_SEV_ENABLED ) && !(sev_status &MSR_AMD64_SEV_ES_ENABLED ); +case CC_ATTR_GUEST_SEV_SNP : +return sev_status &MSR_AMD64_SEV_SNP_ENABLED ; +default :return false; }
arch/x86/include/asm/msr-index.h +2 -0
@@ -484,8 +484,10 @@#define MSR_AMD64_SEV 0xc0010131#define MSR_AMD64_SEV_ENABLED_BIT 0#define MSR_AMD64_SEV_ES_ENABLED_BIT 1 +#define MSR_AMD64_SEV_SNP_ENABLED_BIT 2#define MSR_AMD64_SEV_ENABLED BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)#define MSR_AMD64_SEV_ES_ENABLED BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT) +#define MSR_AMD64_SEV_SNP_ENABLED BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f
arch/x86/mm/mem_encrypt.c +4 -0
@@ -62,6 +62,10 @@ static void print_mem_encrypt_feature_info(void)if (cc_platform_has (CC_ATTR_GUEST_STATE_ENCRYPT ))pr_cont (" SEV-ES" ); +/* Secure Nested Paging */ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) +pr_cont (" SEV-SNP" ); +pr_cont ("\n" ); }
include/linux/cc_platform.h +8 -0
@@ -72,6 +72,14 @@ enum cc_attr {* Examples include TDX guest & SEV. */ CC_ATTR_GUEST_UNROLL_STRING_IO , + +/** +* @CC_ATTR_SEV_SNP: Guest SNP is active. +* +* The platform/OS is running as a guest/virtual machine and actively +* using AMD SEV-SNP features. +*/ + CC_ATTR_GUEST_SEV_SNP, };#ifdef CONFIG_ARCH_HAS_CC_PLATFORM
Signature · 1 line
2.25.1
[tip: x86/sev] x86/mm: Extend cc_attr to include AMD SEV-SNP
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: f742b90e61bb53b27771f64bdae05db03a6ab1f2 Gitweb: https://git.kernel.org/tip/f742b90e61bb53b27771f64bdae05db03a6ab1f2 Author: Brijesh Singh <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:55:49 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:02:34 +02:00
x86/mm: Extend cc_attr to include AMD SEV-SNP
The CC_ATTR_GUEST_SEV_SNP can be used by the guest to query whether the SNP (Secure Nested Paging) feature is active.
--- arch/x86/coco/core.c | 3 +++ arch/x86/include/asm/msr-index.h | 2 ++ arch/x86/mm/mem_encrypt.c | 4 ++++ include/linux/cc_platform.h | 8 ++++++++ 4 files changed, 17 insertions(+)
arch/x86/coco/core.c +3 -0
@@ -57,6 +57,9 @@ static bool amd_cc_platform_has(enum cc_attr attr)return (sev_status &MSR_AMD64_SEV_ENABLED ) && !(sev_status &MSR_AMD64_SEV_ES_ENABLED ); +case CC_ATTR_GUEST_SEV_SNP : +return sev_status &MSR_AMD64_SEV_SNP_ENABLED ; +default :return false; }
arch/x86/include/asm/msr-index.h +2 -0
@@ -502,8 +502,10 @@#define MSR_AMD64_SEV 0xc0010131#define MSR_AMD64_SEV_ENABLED_BIT 0#define MSR_AMD64_SEV_ES_ENABLED_BIT 1 +#define MSR_AMD64_SEV_SNP_ENABLED_BIT 2#define MSR_AMD64_SEV_ENABLED BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)#define MSR_AMD64_SEV_ES_ENABLED BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT) +#define MSR_AMD64_SEV_SNP_ENABLED BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f
arch/x86/mm/mem_encrypt.c +4 -0
@@ -62,6 +62,10 @@ static void print_mem_encrypt_feature_info(void)if (cc_platform_has (CC_ATTR_GUEST_STATE_ENCRYPT ))pr_cont (" SEV-ES" ); +/* Secure Nested Paging */ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) +pr_cont (" SEV-SNP" ); +pr_cont ("\n" ); }
include/linux/cc_platform.h +8 -0
@@ -72,6 +72,14 @@ enum cc_attr {* Examples include TDX guest & SEV. */ CC_ATTR_GUEST_UNROLL_STRING_IO , + +/** +* @CC_ATTR_SEV_SNP: Guest SNP is active. +* +* The platform/OS is running as a guest/virtual machine and actively +* using AMD SEV-SNP features. +*/ + CC_ATTR_GUEST_SEV_SNP, };#ifdef CONFIG_ARCH_HAS_CC_PLATFORM
PATCH v12 10/46 x86/sev: Define the Linux specific guest termination reasons
In reply to Brijesh SinghGHCB specification defines the reason code for reason set 0. The reason codes defined in the set 0 do not cover all possible causes for a guest to request termination.
The reason sets 1 to 255 are reserved for the vendor-specific codes. Reserve the reason set 1 for the Linux guest. Define the error codes for reason set 1 so that one can have meaningful termination reasons and thus better guest failure diagnosis.
While at it, change the sev_es_terminate() to accept the reason set parameter.
--- arch/x86/boot/compressed/sev.c | 6 +++--- arch/x86/include/asm/sev-common.h | 8 ++++++++ arch/x86/kernel/sev-shared.c | 11 ++++------- arch/x86/kernel/sev.c | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-)
arch/x86/boot/compressed/sev.c +3 -3
@@ -119,7 +119,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,static bool early_setup_sev_es (void ) {if (!sev_es_negotiate_protocol ()) -sev_es_terminate (GHCB_SEV_ES_PROT_UNSUPPORTED ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED );if (set_page_decrypted ((unsigned long )&boot_ghcb_page))return false;
@@ -172,7 +172,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)enum es_result result;if (!boot_ghcb && !early_setup_sev_es ()) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb); result =vc_init_em_ctxt (&ctxt, regs, exit_code);
@@ -199,7 +199,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)if (result ==ES_OK )vc_finish_insn (&ctxt);else if (result !=ES_RETRY ) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); }void sev_enable (struct boot_params *bp)
arch/x86/include/asm/sev-common.h +8 -0
@@ -73,9 +73,17 @@/* GHCBData[23:16] */ \ ((((u64)reason_val) & 0xff) << 16)) +/* Error codes from reason set 0 */ +#define SEV_TERM_SET_GEN 0#define GHCB_SEV_ES_GEN_REQ 0#define GHCB_SEV_ES_PROT_UNSUPPORTED 1 +/* Linux-specific reason codes (used with reason set 1) */ +#define SEV_TERM_SET_LINUX 1 +#define GHCB_TERM_REGISTER 0/* GHCB GPA registration failure */ +#define GHCB_TERM_PSC 1/* Page State Change failure */ +#define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ +#define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)/*
arch/x86/kernel/sev-shared.c +4 -7
@@ -24,15 +24,12 @@ static bool __init sev_es_check_cpu_features(void)return true; } -static void __noreturn sev_es_terminate (unsigned int reason) +static void __noreturn sev_es_terminate (unsigned int set,unsigned int reason) {u64 val =GHCB_MSR_TERM_REQ ; -/* -* Tell the hypervisor what went wrong - only reason-set 0 is -* currently supported. -*/ - val |=GHCB_SEV_TERM_REASON (0 , reason); +/* Tell the hypervisor what went wrong. */ + val |=GHCB_SEV_TERM_REASON (set, reason);/* Request Guest Termination from Hypvervisor */ sev_es_wr_ghcb_msr (val);
@@ -221,7 +218,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) fail:/* Terminate the guest */ -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); } static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
arch/x86/kernel/sev.c +2 -2
@@ -1337,7 +1337,7 @@ DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication)show_regs (regs);/* Ask hypervisor to sev_es_terminate */ -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );/* If that fails and we get here - just panic */ panic ("Returned from Terminate-Request to Hypervisor\n" );
@@ -1385,7 +1385,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)/* Do initial setup or terminate the guest */ if (unlikely (boot_ghcb ==NULL && !sev_es_setup_ghcb ())) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb);
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Define the Linux-specific guest termination reasons
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 6c0f74d678c94060932683738b3e227995b363d3 Gitweb: https://git.kernel.org/tip/6c0f74d678c94060932683738b3e227995b363d3 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:04 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:02:41 +02:00
x86/sev: Define the Linux-specific guest termination reasons
The GHCB specification defines the reason code for reason set 0. The reason codes defined in the set 0 do not cover all possible causes for a guest to request termination.
The reason sets 1 to 255 are reserved for the vendor-specific codes. Reserve the reason set 1 for the Linux guest. Define the error codes for reason set 1 so that one can have meaningful termination reasons and thus better guest failure diagnosis.
While at it, change sev_es_terminate() to accept a reason set parameter.
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/sev.c | 6 +++--- arch/x86/include/asm/sev-common.h | 8 ++++++++ arch/x86/kernel/sev-shared.c | 11 ++++------- arch/x86/kernel/sev.c | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-)
arch/x86/boot/compressed/sev.c +3 -3
@@ -119,7 +119,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,static bool early_setup_sev_es (void ) {if (!sev_es_negotiate_protocol ()) -sev_es_terminate (GHCB_SEV_ES_PROT_UNSUPPORTED ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED );if (set_page_decrypted ((unsigned long )&boot_ghcb_page))return false;
@@ -172,7 +172,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)enum es_result result;if (!boot_ghcb && !early_setup_sev_es ()) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb); result =vc_init_em_ctxt (&ctxt, regs, exit_code);
@@ -199,7 +199,7 @@ finish:if (result ==ES_OK )vc_finish_insn (&ctxt);else if (result !=ES_RETRY ) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); }void sev_enable (struct boot_params *bp)
arch/x86/include/asm/sev-common.h +8 -0
@@ -73,9 +73,17 @@/* GHCBData[23:16] */ \ ((((u64)reason_val) & 0xff) << 16)) +/* Error codes from reason set 0 */ +#define SEV_TERM_SET_GEN 0#define GHCB_SEV_ES_GEN_REQ 0#define GHCB_SEV_ES_PROT_UNSUPPORTED 1 +/* Linux-specific reason codes (used with reason set 1) */ +#define SEV_TERM_SET_LINUX 1 +#define GHCB_TERM_REGISTER 0/* GHCB GPA registration failure */ +#define GHCB_TERM_PSC 1/* Page State Change failure */ +#define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ +#define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)/*
arch/x86/kernel/sev-shared.c +4 -7
@@ -24,15 +24,12 @@ static bool __init sev_es_check_cpu_features(void)return true; } -static void __noreturn sev_es_terminate (unsigned int reason) +static void __noreturn sev_es_terminate (unsigned int set,unsigned int reason) {u64 val =GHCB_MSR_TERM_REQ ; -/* -* Tell the hypervisor what went wrong - only reason-set 0 is -* currently supported. -*/ - val |=GHCB_SEV_TERM_REASON (0 , reason); +/* Tell the hypervisor what went wrong. */ + val |=GHCB_SEV_TERM_REASON (set, reason);/* Request Guest Termination from Hypvervisor */ sev_es_wr_ghcb_msr (val);
@@ -221,7 +218,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) fail:/* Terminate the guest */ -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); } static enum es_result vc_insn_string_read(struct es_em_ctxt *ctxt,
arch/x86/kernel/sev.c +2 -2
@@ -1337,7 +1337,7 @@ DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication)show_regs (regs);/* Ask hypervisor to sev_es_terminate */ -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );/* If that fails and we get here - just panic */ panic ("Returned from Terminate-Request to Hypervisor\n" );
@@ -1385,7 +1385,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)/* Do initial setup or terminate the guest */ if (unlikely (boot_ghcb ==NULL && !sev_es_setup_ghcb ())) -sev_es_terminate (GHCB_SEV_ES_GEN_REQ ); +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb);
PATCH v12 11/46 x86/sev: Save the negotiated GHCB version
In reply to Brijesh SinghThe SEV-ES guest calls the sev_es_negotiate_protocol() to negotiate the GHCB protocol version before establishing the GHCB. Cache the negotiated GHCB version so that it can be used later.
--- arch/x86/include/asm/sev.h | 2 +- arch/x86/kernel/sev-shared.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-)
arch/x86/include/asm/sev.h +1 -1
@@ -12,7 +12,7 @@#include <asm/insn.h> #include <asm/sev-common.h> -#define GHCB_PROTO_OUR 0x0001UL +#define GHCB_PROTOCOL_MIN 1ULL#define GHCB_PROTOCOL_MAX 1ULL#define GHCB_DEFAULT_USAGE 0ULL
arch/x86/kernel/sev-shared.c +14 -3
@@ -14,6 +14,15 @@#define has_cpuflag (f) boot_cpu_has(f)#endif +/* +* Since feature negotiation related variables are set early in the boot +* process they must reside in the .data section so as not to be zeroed +* out when the .bss section is later cleared. +* +* GHCB protocol version negotiated with the hypervisor. +*/ +static u16 ghcb_version__ro_after_init ; +static bool __init sev_es_check_cpu_features (void ) {if (!has_cpuflag (X86_FEATURE_RDRAND )) {
@@ -51,10 +60,12 @@ static bool sev_es_negotiate_protocol(void)if (GHCB_MSR_INFO (val) !=GHCB_MSR_SEV_INFO_RESP )return false; -if (GHCB_MSR_PROTO_MAX (val) <GHCB_PROTO_OUR || -GHCB_MSR_PROTO_MIN (val) >GHCB_PROTO_OUR ) +if (GHCB_MSR_PROTO_MAX (val) <GHCB_PROTOCOL_MIN || +GHCB_MSR_PROTO_MIN (val) >GHCB_PROTOCOL_MAX )return false; + ghcb_version =min_t (size_t,GHCB_MSR_PROTO_MAX (val),GHCB_PROTOCOL_MAX ); +return true; }
@@ -127,7 +138,7 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr, u64 exit_info_1, u64 exit_info_2) {/* Fill in protocol and format specifiers */ - ghcb->protocol_version =GHCB_PROTOCOL_MAX ; + ghcb->protocol_version = ghcb_version; ghcb->ghcb_usage =GHCB_DEFAULT_USAGE ;ghcb_set_sw_exit_code (ghcb, exit_code);
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Save the negotiated GHCB version
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 2ea29c5abbc27147c2d9e2ab5e05436aca706b65 Gitweb: https://git.kernel.org/tip/2ea29c5abbc27147c2d9e2ab5e05436aca706b65 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:05 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:10:18 +02:00
x86/sev: Save the negotiated GHCB version
The SEV-ES guest calls sev_es_negotiate_protocol() to negotiate the GHCB protocol version before establishing the GHCB. Cache the negotiated GHCB version so that it can be used later.
--- arch/x86/include/asm/sev.h | 2 +- arch/x86/kernel/sev-shared.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-)
arch/x86/include/asm/sev.h +1 -1
@@ -12,7 +12,7 @@#include <asm/insn.h> #include <asm/sev-common.h> -#define GHCB_PROTO_OUR 0x0001UL +#define GHCB_PROTOCOL_MIN 1ULL#define GHCB_PROTOCOL_MAX 1ULL#define GHCB_DEFAULT_USAGE 0ULL
arch/x86/kernel/sev-shared.c +14 -3
@@ -14,6 +14,15 @@#define has_cpuflag (f) boot_cpu_has(f)#endif +/* +* Since feature negotiation related variables are set early in the boot +* process they must reside in the .data section so as not to be zeroed +* out when the .bss section is later cleared. +* +* GHCB protocol version negotiated with the hypervisor. +*/ +static u16 ghcb_version__ro_after_init ; +static bool __init sev_es_check_cpu_features (void ) {if (!has_cpuflag (X86_FEATURE_RDRAND )) {
@@ -51,10 +60,12 @@ static bool sev_es_negotiate_protocol(void)if (GHCB_MSR_INFO (val) !=GHCB_MSR_SEV_INFO_RESP )return false; -if (GHCB_MSR_PROTO_MAX (val) <GHCB_PROTO_OUR || -GHCB_MSR_PROTO_MIN (val) >GHCB_PROTO_OUR ) +if (GHCB_MSR_PROTO_MAX (val) <GHCB_PROTOCOL_MIN || +GHCB_MSR_PROTO_MIN (val) >GHCB_PROTOCOL_MAX )return false; + ghcb_version =min_t (size_t,GHCB_MSR_PROTO_MAX (val),GHCB_PROTOCOL_MAX ); +return true; }
@@ -127,7 +138,7 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr, u64 exit_info_1, u64 exit_info_2) {/* Fill in protocol and format specifiers */ - ghcb->protocol_version =GHCB_PROTOCOL_MAX ; + ghcb->protocol_version = ghcb_version; ghcb->ghcb_usage =GHCB_DEFAULT_USAGE ;ghcb_set_sw_exit_code (ghcb, exit_code);
PATCH v12 12/46 x86/sev: Check SEV-SNP features support
In reply to Brijesh SinghVersion 2 of the GHCB specification added the advertisement of features that are supported by the hypervisor. If hypervisor supports the SEV-SNP then it must set the SEV-SNP features bit to indicate that the base SEV-SNP is supported.
Check the SEV-SNP feature while establishing the GHCB, if failed, terminate the guest.
Version 2 of GHCB specification adds several new NAEs, most of them are optional except the hypervisor feature. Now that hypervisor feature NAE is implemented, so bump the GHCB maximum support protocol version.
While at it, move the GHCB protocol negotiation check from VC exception handler to sev_enable() so that all feature detection happens before the first VC exception.
While at it, document why GHCB page cannot be setup from the load_stage2_idt().
--- arch/x86/boot/compressed/idt_64.c | 18 +++++++++++++++++- arch/x86/boot/compressed/sev.c | 20 +++++++++++++++----- arch/x86/include/asm/sev-common.h | 6 ++++++ arch/x86/include/asm/sev.h | 2 +- arch/x86/include/uapi/asm/svm.h | 2 ++ arch/x86/kernel/sev-shared.c | 20 ++++++++++++++++++++ arch/x86/kernel/sev.c | 14 ++++++++++++++ 7 files changed, 75 insertions(+), 7 deletions(-)
arch/x86/boot/compressed/idt_64.c +17 -1
@@ -39,7 +39,23 @@ void load_stage1_idt(void)load_boot_idt (&boot_idt_desc); } -/* Setup IDT after kernel jumping to .Lrelocated */ +/* +* Setup IDT after kernel jumping to .Lrelocated. +* +* initialize_identity_maps() needs a #PF handler to be setup +* in order to be able to fault-in identity mapping ranges; see +* do_boot_page_fault(). +* +* This #PF handler setup needs to happen in load_stage2_idt() where the +* IDT is loaded and there the #VC IDT entry gets setup too. +* +* In order to be able to handle #VCs, one needs a GHCB which +* gets setup with an already set up pagetable, which is done in +* initialize_identity_maps(). And there's the catch 22: the boot #VC +* handler do_boot_stage2_vc() needs to call early_setup_ghcb() itself +* (and, especially set_page_decrypted()) because the SEV-ES setup code +* cannot initialize a GHCB as there's no #PF handler yet... +*/ void load_stage2_idt (void ) { boot_idt_desc.address = (unsigned long )boot_idt;
arch/x86/boot/compressed/sev.c +15 -5
@@ -116,11 +116,8 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,/* Include code for early handlers */ #include "../../kernel/sev-shared.c" -static bool early_setup_sev_es (void ) +static bool early_setup_ghcb (void ) { -if (!sev_es_negotiate_protocol ()) -sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED ); -if (set_page_decrypted ((unsigned long )&boot_ghcb_page))return false;
@@ -171,7 +168,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)struct es_em_ctxt ctxt;enum es_result result; -if (!boot_ghcb && !early_setup_sev_es ()) +if (!boot_ghcb && !early_setup_ghcb ())sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb);
@@ -235,5 +232,18 @@ void sev_enable(struct boot_params *bp)if (!(sev_status &MSR_AMD64_SEV_ENABLED ))return ; +/* Negotiate the GHCB protocol version. */ +if (sev_status &MSR_AMD64_SEV_ES_ENABLED ) { +if (!sev_es_negotiate_protocol ()) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED ); + } + +/* +* SNP is supported in v2 of the GHCB spec which mandates support for HV +* features. +*/ +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED && !(get_hv_features () &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + sme_me_mask =BIT_ULL (ebx &0x3f ); }
arch/x86/include/asm/sev-common.h +6 -0
@@ -60,6 +60,11 @@/* GHCB Hypervisor Feature Request/Response */ #define GHCB_MSR_HV_FT_REQ 0x080#define GHCB_MSR_HV_FT_RESP 0x081 +#define GHCB_MSR_HV_FT_RESP_VAL (v) \ +/* GHCBData[63:12] */ \ + (((u64)(v) & GENMASK_ULL(63, 12)) >> 12) + +#define GHCB_HV_FT_SNP BIT_ULL(0)#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12
@@ -77,6 +82,7 @@#define SEV_TERM_SET_GEN 0#define GHCB_SEV_ES_GEN_REQ 0#define GHCB_SEV_ES_PROT_UNSUPPORTED 1 +#define GHCB_SNP_UNSUPPORTED 2/* Linux-specific reason codes (used with reason set 1) */ #define SEV_TERM_SET_LINUX 1
arch/x86/include/asm/sev.h +1 -1
@@ -13,7 +13,7 @@#include <asm/sev-common.h> #define GHCB_PROTOCOL_MIN 1ULL -#define GHCB_PROTOCOL_MAX 1ULL +#define GHCB_PROTOCOL_MAX 2ULL#define GHCB_DEFAULT_USAGE 0ULL#define VMGEXIT () { asm volatile("rep; vmmcall\n\r"); }
arch/x86/include/uapi/asm/svm.h +2 -0
@@ -108,6 +108,7 @@#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 +#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff/* Exit code reserved for hypervisor/software use */
@@ -218,6 +219,7 @@ { SVM_VMGEXIT_NMI_COMPLETE, "vmgexit_nmi_complete" }, \ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ + { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev-shared.c +20 -0
@@ -48,6 +48,26 @@ static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason) asmvolatile ("hlt\n" : : :"memory" ); } +/* +* The hypervisor features are available from GHCB version 2 onward. +*/ +static u64 get_hv_features (void ) +{ +u64 val; + +if (ghcb_version <2 ) +return 0 ; + +sev_es_wr_ghcb_msr (GHCB_MSR_HV_FT_REQ ); +VMGEXIT (); + + val =sev_es_rd_ghcb_msr (); +if (GHCB_RESP_CODE (val) !=GHCB_MSR_HV_FT_RESP ) +return 0 ; + +return GHCB_MSR_HV_FT_RESP_VAL (val); +} +static bool sev_es_negotiate_protocol (void ) {u64 val;
arch/x86/kernel/sev.c +14 -0
@@ -43,6 +43,9 @@ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);*/ static struct ghcb __initdata *boot_ghcb; +/* Bitmap of SEV features supported by the hypervisor */ +static u64 sev_hv_features__ro_after_init ; +/* #VC handler runtime per-CPU data */ struct sev_es_runtime_data {struct ghcb ghcb_page;
@@ -766,6 +769,17 @@ void __init sev_es_init_vc_handling(void)if (!sev_es_check_cpu_features ())panic ("SEV-ES CPU Features missing" ); +/* +* SNP is supported in v2 of the GHCB spec which mandates support for HV +* features. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) { + sev_hv_features =get_hv_features (); + +if (!(sev_hv_features &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + } +/* Enable SEV-ES special handling */ static_branch_enable (&sev_es_enable_key);
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Check SEV-SNP features support
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: cbd3d4f7c4e5a93edae68e5142a269368fde77d6 Gitweb: https://git.kernel.org/tip/cbd3d4f7c4e5a93edae68e5142a269368fde77d6 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:06 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:10:23 +02:00
x86/sev: Check SEV-SNP features support
Version 2 of the GHCB specification added the advertisement of features that are supported by the hypervisor. If the hypervisor supports SEV-SNP then it must set the SEV-SNP features bit to indicate that the base functionality is supported.
Check that feature bit while establishing the GHCB; if failed, terminate the guest.
Version 2 of the GHCB specification adds several new Non-Automatic Exits (NAEs), most of them are optional except the hypervisor feature. Now that the hypervisor feature NAE is implemented, bump the GHCB maximum supported protocol version.
While at it, move the GHCB protocol negotiation check from the #VC exception handler to sev_enable() so that all feature detection happens before the first #VC exception.
While at it, document why the GHCB page cannot be setup from load_stage2_idt().
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/idt_64.c | 18 +++++++++++++++++- arch/x86/boot/compressed/sev.c | 20 +++++++++++++++----- arch/x86/include/asm/sev-common.h | 6 ++++++ arch/x86/include/asm/sev.h | 2 +- arch/x86/include/uapi/asm/svm.h | 2 ++ arch/x86/kernel/sev-shared.c | 20 ++++++++++++++++++++ arch/x86/kernel/sev.c | 14 ++++++++++++++ 7 files changed, 75 insertions(+), 7 deletions(-)
arch/x86/boot/compressed/idt_64.c +17 -1
@@ -39,7 +39,23 @@ void load_stage1_idt(void)load_boot_idt (&boot_idt_desc); } -/* Setup IDT after kernel jumping to .Lrelocated */ +/* +* Setup IDT after kernel jumping to .Lrelocated. +* +* initialize_identity_maps() needs a #PF handler to be setup +* in order to be able to fault-in identity mapping ranges; see +* do_boot_page_fault(). +* +* This #PF handler setup needs to happen in load_stage2_idt() where the +* IDT is loaded and there the #VC IDT entry gets setup too. +* +* In order to be able to handle #VCs, one needs a GHCB which +* gets setup with an already set up pagetable, which is done in +* initialize_identity_maps(). And there's the catch 22: the boot #VC +* handler do_boot_stage2_vc() needs to call early_setup_ghcb() itself +* (and, especially set_page_decrypted()) because the SEV-ES setup code +* cannot initialize a GHCB as there's no #PF handler yet... +*/ void load_stage2_idt (void ) { boot_idt_desc.address = (unsigned long )boot_idt;
arch/x86/boot/compressed/sev.c +15 -5
@@ -116,11 +116,8 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,/* Include code for early handlers */ #include "../../kernel/sev-shared.c" -static bool early_setup_sev_es (void ) +static bool early_setup_ghcb (void ) { -if (!sev_es_negotiate_protocol ()) -sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED ); -if (set_page_decrypted ((unsigned long )&boot_ghcb_page))return false;
@@ -171,7 +168,7 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)struct es_em_ctxt ctxt;enum es_result result; -if (!boot_ghcb && !early_setup_sev_es ()) +if (!boot_ghcb && !early_setup_ghcb ())sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ );vc_ghcb_invalidate (boot_ghcb);
@@ -235,5 +232,18 @@ void sev_enable(struct boot_params *bp)if (!(sev_status &MSR_AMD64_SEV_ENABLED ))return ; +/* Negotiate the GHCB protocol version. */ +if (sev_status &MSR_AMD64_SEV_ES_ENABLED ) { +if (!sev_es_negotiate_protocol ()) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_PROT_UNSUPPORTED ); + } + +/* +* SNP is supported in v2 of the GHCB spec which mandates support for HV +* features. +*/ +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED && !(get_hv_features () &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + sme_me_mask =BIT_ULL (ebx &0x3f ); }
arch/x86/include/asm/sev-common.h +6 -0
@@ -60,6 +60,11 @@/* GHCB Hypervisor Feature Request/Response */ #define GHCB_MSR_HV_FT_REQ 0x080#define GHCB_MSR_HV_FT_RESP 0x081 +#define GHCB_MSR_HV_FT_RESP_VAL (v) \ +/* GHCBData[63:12] */ \ + (((u64)(v) & GENMASK_ULL(63, 12)) >> 12) + +#define GHCB_HV_FT_SNP BIT_ULL(0)#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12
@@ -77,6 +82,7 @@#define SEV_TERM_SET_GEN 0#define GHCB_SEV_ES_GEN_REQ 0#define GHCB_SEV_ES_PROT_UNSUPPORTED 1 +#define GHCB_SNP_UNSUPPORTED 2/* Linux-specific reason codes (used with reason set 1) */ #define SEV_TERM_SET_LINUX 1
arch/x86/include/asm/sev.h +1 -1
@@ -13,7 +13,7 @@#include <asm/sev-common.h> #define GHCB_PROTOCOL_MIN 1ULL -#define GHCB_PROTOCOL_MAX 1ULL +#define GHCB_PROTOCOL_MAX 2ULL#define GHCB_DEFAULT_USAGE 0ULL#define VMGEXIT () { asm volatile("rep; vmmcall\n\r"); }
arch/x86/include/uapi/asm/svm.h +2 -0
@@ -108,6 +108,7 @@#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 +#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff/* Exit code reserved for hypervisor/software use */
@@ -218,6 +219,7 @@ { SVM_VMGEXIT_NMI_COMPLETE, "vmgexit_nmi_complete" }, \ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ + { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev-shared.c +20 -0
@@ -48,6 +48,26 @@ static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason) asmvolatile ("hlt\n" : : :"memory" ); } +/* +* The hypervisor features are available from GHCB version 2 onward. +*/ +static u64 get_hv_features (void ) +{ +u64 val; + +if (ghcb_version <2 ) +return 0 ; + +sev_es_wr_ghcb_msr (GHCB_MSR_HV_FT_REQ ); +VMGEXIT (); + + val =sev_es_rd_ghcb_msr (); +if (GHCB_RESP_CODE (val) !=GHCB_MSR_HV_FT_RESP ) +return 0 ; + +return GHCB_MSR_HV_FT_RESP_VAL (val); +} +static bool sev_es_negotiate_protocol (void ) {u64 val;
arch/x86/kernel/sev.c +14 -0
@@ -43,6 +43,9 @@ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);*/ static struct ghcb __initdata *boot_ghcb; +/* Bitmap of SEV features supported by the hypervisor */ +static u64 sev_hv_features__ro_after_init ; +/* #VC handler runtime per-CPU data */ struct sev_es_runtime_data {struct ghcb ghcb_page;
@@ -766,6 +769,17 @@ void __init sev_es_init_vc_handling(void)if (!sev_es_check_cpu_features ())panic ("SEV-ES CPU Features missing" ); +/* +* SNP is supported in v2 of the GHCB spec which mandates support for HV +* features. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) { + sev_hv_features =get_hv_features (); + +if (!(sev_hv_features &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + } +/* Enable SEV-ES special handling */ static_branch_enable (&sev_es_enable_key);
PATCH v12 13/46 x86/sev: Add a helper for the PVALIDATE instruction
In reply to Brijesh SinghAn SNP-active guest uses the PVALIDATE instruction to validate or rescind the validation of a guest page’s RMP entry. Upon completion, a return code is stored in EAX and rFLAGS bits are set based on the return code. If the instruction completed successfully, the CF indicates if the content of the RMP were changed or not.
See AMD APM Volume 3 for additional details.
--- arch/x86/include/asm/sev.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
arch/x86/include/asm/sev.h +21 -0
@@ -60,6 +60,9 @@ extern void vc_no_ghcb(void);extern void vc_boot_ghcb (void );extern bool handle_vc_boot_ghcb (struct pt_regs *regs); +/* Software defined (when rFlags.CF = 1) */ +#define PVALIDATE_FAIL_NOUPDATE 255 +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -87,12 +90,30 @@ extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,struct es_em_ctxt *ctxt, u64 exit_code, u64 exit_info_1, u64 exit_info_2); +static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) +{ +bool no_rmpupdate; +int rc; + +/* "pvalidate" mnemonic support in binutils 2.36 and newer */ + asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t" + CC_SET(c) + : CC_OUT(c) (no_rmpupdate), "=a"(rc) + : "a"(vaddr), "c"(rmp_psize), "d"(validate) + : "memory", "cc"); + +if (no_rmpupdate) +return PVALIDATE_FAIL_NOUPDATE ; + +return rc; +}#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }static inline int sev_es_setup_ap_jump_table (struct real_mode_header *rmh) {return 0 ; }static inline void sev_es_nmi_complete (void ) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; } +static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }#endif #endif
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Add a helper for the PVALIDATE instruction
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 0bd6f1e526070271dbe0f626b123b4f6b01dc79c Gitweb: https://git.kernel.org/tip/0bd6f1e526070271dbe0f626b123b4f6b01dc79c Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:07 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:10:30 +02:00
x86/sev: Add a helper for the PVALIDATE instruction
An SNP-active guest uses the PVALIDATE instruction to validate or rescind the validation of a guest page’s RMP entry. Upon completion, a return code is stored in EAX and rFLAGS bits are set based on the return code. If the instruction completed successfully, the carry flag (CF) indicates if the content of the RMP were changed or not.
See AMD APM Volume 3 for additional details.
--- arch/x86/include/asm/sev.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
arch/x86/include/asm/sev.h +21 -0
@@ -60,6 +60,9 @@ extern void vc_no_ghcb(void);extern void vc_boot_ghcb (void );extern bool handle_vc_boot_ghcb (struct pt_regs *regs); +/* Software defined (when rFlags.CF = 1) */ +#define PVALIDATE_FAIL_NOUPDATE 255 +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -87,12 +90,30 @@ extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,struct es_em_ctxt *ctxt, u64 exit_code, u64 exit_info_1, u64 exit_info_2); +static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) +{ +bool no_rmpupdate; +int rc; + +/* "pvalidate" mnemonic support in binutils 2.36 and newer */ + asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t" + CC_SET(c) + : CC_OUT(c) (no_rmpupdate), "=a"(rc) + : "a"(vaddr), "c"(rmp_psize), "d"(validate) + : "memory", "cc"); + +if (no_rmpupdate) +return PVALIDATE_FAIL_NOUPDATE ; + +return rc; +}#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }static inline int sev_es_setup_ap_jump_table (struct real_mode_header *rmh) {return 0 ; }static inline void sev_es_nmi_complete (void ) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; } +static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }#endif #endif
PATCH v12 14/46 x86/sev: Check the vmpl level
In reply to Brijesh SinghVirtual Machine Privilege Level (VMPL) feature in the SEV-SNP architecture allows a guest VM to divide its address space into four levels. The level can be used to provide the hardware isolated abstraction layers with a VM. The VMPL0 is the highest privilege, and VMPL3 is the least privilege. Certain operations must be done by the VMPL0 software, such as:
* Validate or invalidate memory range (PVALIDATE instruction)
* Allocate VMSA page (RMPADJUST instruction when VMSA=1)
The initial SEV-SNP support requires that the guest kernel is running on VMPL0. Add a check to make sure that kernel is running at VMPL0 before continuing the boot. There is no easy method to query the current VMPL level, so use the RMPADJUST instruction to determine whether the guest is running at the VMPL0.
--- arch/x86/boot/compressed/sev.c | 28 ++++++++++++++++++++++++++-- arch/x86/include/asm/sev-common.h | 1 + arch/x86/include/asm/sev.h | 16 ++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
arch/x86/boot/compressed/sev.c +26 -2
@@ -199,6 +199,26 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); } +static void enforce_vmpl0 (void ) +{ +u64 attrs; +int err; + +/* +* RMPADJUST modifies RMP permissions of a lesser-privileged (numerically +* higher) privilege level. Here, clear the VMPL1 permission mask of the +* GHCB page. If the guest is not running at VMPL0, this will fail. +* +* If the guest is running at VMPL0, it will succeed. Even if that operation +* modifies permission bits, it is still ok to do currently because Linux +* SNP guests are supported only on VMPL0 so VMPL1 or higher permission masks +* changing is a don't-care. +*/ + attrs =1 ; +if (rmpadjust ((unsigned long )&boot_ghcb_page,RMP_PG_SIZE_4K , attrs)) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_NOT_VMPL0 ); +} +void sev_enable (struct boot_params *bp) {unsigned int eax, ebx, ecx, edx;
@@ -242,8 +262,12 @@ void sev_enable(struct boot_params *bp)* SNP is supported in v2 of the GHCB spec which mandates support for HV * features. */ -if (sev_status &MSR_AMD64_SEV_SNP_ENABLED && !(get_hv_features () &GHCB_HV_FT_SNP )) -sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED ) { +if (!(get_hv_features () &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + +enforce_vmpl0 (); + } sme_me_mask =BIT_ULL (ebx &0x3f ); }
arch/x86/include/asm/sev-common.h +1 -0
@@ -89,6 +89,7 @@#define GHCB_TERM_REGISTER 0/* GHCB GPA registration failure */ #define GHCB_TERM_PSC 1/* Page State Change failure */ #define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ +#define GHCB_TERM_NOT_VMPL0 3/* SNP guest is not running at VMPL-0 */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/include/asm/sev.h +16 -0
@@ -63,6 +63,9 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);/* Software defined (when rFlags.CF = 1) */ #define PVALIDATE_FAIL_NOUPDATE 255 +/* RMP page size */ +#define RMP_PG_SIZE_4K 0 +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -90,6 +93,18 @@ extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,struct es_em_ctxt *ctxt, u64 exit_code, u64 exit_info_1, u64 exit_info_2); +static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) +{ +int rc; + +/* "rmpadjust" mnemonic support in binutils 2.36 and newer */ + asmvolatile (".byte 0xF3,0x0F,0x01,0xFE\n\t" + :"=a" (rc) + :"a" (vaddr),"c" (rmp_psize),"d" (attrs) + :"memory" ,"cc" ); + +return rc; +}static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {bool no_rmpupdate;
@@ -114,6 +129,7 @@ static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { retstatic inline void sev_es_nmi_complete (void ) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; } +static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; }#endif #endif
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Check the VMPL level
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 81cc3df9a90e7817494421ecc48ede6bd5e8132b Gitweb: https://git.kernel.org/tip/81cc3df9a90e7817494421ecc48ede6bd5e8132b Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:08 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:10:34 +02:00
x86/sev: Check the VMPL level
The Virtual Machine Privilege Level (VMPL) feature in the SEV-SNP architecture allows a guest VM to divide its address space into four levels. The level can be used to provide hardware isolated abstraction layers within a VM. VMPL0 is the highest privilege level, and VMPL3 is the least privilege level. Certain operations must be done by the VMPL0 software, such as:
* Validate or invalidate memory range (PVALIDATE instruction)
* Allocate VMSA page (RMPADJUST instruction when VMSA=1)
The initial SNP support requires that the guest kernel is running at VMPL0. Add such a check to verify the guest is running at level 0 before continuing the boot. There is no easy method to query the current VMPL level, so use the RMPADJUST instruction to determine whether the guest is running at the VMPL0.
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/sev.c | 28 ++++++++++++++++++++++++++-- arch/x86/include/asm/sev-common.h | 1 + arch/x86/include/asm/sev.h | 16 ++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
arch/x86/boot/compressed/sev.c +26 -2
@@ -199,6 +199,26 @@ finish:sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SEV_ES_GEN_REQ ); } +static void enforce_vmpl0 (void ) +{ +u64 attrs; +int err; + +/* +* RMPADJUST modifies RMP permissions of a lesser-privileged (numerically +* higher) privilege level. Here, clear the VMPL1 permission mask of the +* GHCB page. If the guest is not running at VMPL0, this will fail. +* +* If the guest is running at VMPL0, it will succeed. Even if that operation +* modifies permission bits, it is still ok to do so currently because Linux +* SNP guests are supported only on VMPL0 so VMPL1 or higher permission masks +* changing is a don't-care. +*/ + attrs =1 ; +if (rmpadjust ((unsigned long )&boot_ghcb_page,RMP_PG_SIZE_4K , attrs)) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_NOT_VMPL0 ); +} +void sev_enable (struct boot_params *bp) {unsigned int eax, ebx, ecx, edx;
@@ -242,8 +262,12 @@ void sev_enable(struct boot_params *bp)* SNP is supported in v2 of the GHCB spec which mandates support for HV * features. */ -if (sev_status &MSR_AMD64_SEV_SNP_ENABLED && !(get_hv_features () &GHCB_HV_FT_SNP )) -sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED ) { +if (!(get_hv_features () &GHCB_HV_FT_SNP )) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + +enforce_vmpl0 (); + } sme_me_mask =BIT_ULL (ebx &0x3f ); }
arch/x86/include/asm/sev-common.h +1 -0
@@ -89,6 +89,7 @@#define GHCB_TERM_REGISTER 0/* GHCB GPA registration failure */ #define GHCB_TERM_PSC 1/* Page State Change failure */ #define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ +#define GHCB_TERM_NOT_VMPL0 3/* SNP guest is not running at VMPL-0 */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/include/asm/sev.h +16 -0
@@ -63,6 +63,9 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);/* Software defined (when rFlags.CF = 1) */ #define PVALIDATE_FAIL_NOUPDATE 255 +/* RMP page size */ +#define RMP_PG_SIZE_4K 0 +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -90,6 +93,18 @@ extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,struct es_em_ctxt *ctxt, u64 exit_code, u64 exit_info_1, u64 exit_info_2); +static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) +{ +int rc; + +/* "rmpadjust" mnemonic support in binutils 2.36 and newer */ + asmvolatile (".byte 0xF3,0x0F,0x01,0xFE\n\t" + :"=a" (rc) + :"a" (vaddr),"c" (rmp_psize),"d" (attrs) + :"memory" ,"cc" ); + +return rc; +}static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {bool no_rmpupdate;
@@ -114,6 +129,7 @@ static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { retstatic inline void sev_es_nmi_complete (void ) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; } +static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; }#endif #endif
PATCH v12 15/46 x86/compressed: Add helper for validating pages in the decompression stage
In reply to Brijesh SinghMany of the integrity guarantees of SEV-SNP are enforced through the Reverse Map Table (RMP). Each RMP entry contains the GPA at which a particular page of DRAM should be mapped. The VMs can request the hypervisor to add pages in the RMP table via the Page State Change VMGEXIT defined in the GHCB specification. Inside each RMP entry is a Validated flag; this flag is automatically cleared to 0 by the CPU hardware when a new RMP entry is created for a guest. Each VM page can be either validated or invalidated, as indicated by the Validated flag in the RMP entry. Memory access to a private page that is not validated generates a #VC. A VM must use PVALIDATE instruction to validate the private page before using it.
To maintain the security guarantee of SEV-SNP guests, when transitioning pages from private to shared, the guest must invalidate the pages before asking the hypervisor to change the page state to shared in the RMP table.
After the pages are mapped private in the page table, the guest must issue a page state change VMGEXIT to make the pages private in the RMP table and validate it.
On boot, BIOS should have validated the entire system memory. During the kernel decompression stage, the early_setup_ghcb() uses the set_page_decrypted() to make the GHCB page shared (i.e clear encryption attribute). And while exiting from the decompression, it calls the set_page_encrypted() to make the page private.
Add snp_set_page_{private,shared}() helpers that are used by the set_page_{decrypted,encrypted}() to change the page state in the RMP table.
--- arch/x86/boot/compressed/ident_map_64.c | 18 +++++++++- arch/x86/boot/compressed/misc.h | 4 +++ arch/x86/boot/compressed/sev.c | 46 +++++++++++++++++++++++++ arch/x86/include/asm/sev-common.h | 26 ++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/ident_map_64.c +17 -1
@@ -275,15 +275,31 @@ static int set_clr_page_flags(struct x86_mapping_info *info,* Changing encryption attributes of a page requires to flush it from * the caches. */ -if ((set | clr) & _PAGE_ENC) +if ((set | clr) & _PAGE_ENC) {clflush_page (address); +/* +* If the encryption attribute is being cleared, then change +* the page state to shared in the RMP table. +*/ +if (clr) +snp_set_page_shared (__pa (address &PAGE_MASK )); + } +/* Update PTE */ pte = *ptep; pte =pte_set_flags (pte, set); pte =pte_clear_flags (pte, clr);set_pte (ptep, pte); +/* +* If the encryption attribute is being set, then change the page state to +* private in the RMP entry. The page state change must be done after the PTE +* is updated. +*/ +if (set & _PAGE_ENC) +snp_set_page_private (__pa (address &PAGE_MASK )); +/* Flush TLB after changing encryption attribute */ write_cr3 (top_level_pgt);
arch/x86/boot/compressed/misc.h +4 -0
@@ -124,6 +124,8 @@ static inline void console_init(void)void sev_enable (struct boot_params *bp);void sev_es_shutdown_ghcb (void );extern bool sev_es_check_ghcb_fault (unsigned long address); +void snp_set_page_private (unsigned long paddr); +void snp_set_page_shared (unsigned long paddr);#else static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }
@@ -131,6 +133,8 @@ static inline bool sev_es_check_ghcb_fault(unsigned long address) {return false; } +static inline void snp_set_page_private (unsigned long paddr) { } +static inline void snp_set_page_shared (unsigned long paddr) { }#endif /* acpi.c */
arch/x86/boot/compressed/sev.c +46 -0
52 lines not on this page · raw message
arch/x86/include/asm/sev-common.h +26 -0
@@ -57,6 +57,32 @@#define GHCB_MSR_AP_RESET_HOLD_REQ 0x006#define GHCB_MSR_AP_RESET_HOLD_RESP 0x007 +/* +* SNP Page State Change Operation +* +* GHCBData[55:52] - Page operation: +* 0x0001 Page assignment, Private +* 0x0002 Page assignment, Shared +*/ +enum psc_op { +SNP_PAGE_STATE_PRIVATE =1 , +SNP_PAGE_STATE_SHARED , +}; + +#define GHCB_MSR_PSC_REQ 0x014 +#define GHCB_MSR_PSC_REQ_GFN (gfn, op) \ +/* GHCBData[55:52] */ \ + (((u64)((op) & 0xf) << 52) | \ +/* GHCBData[51:12] */ \ + ((u64)((gfn) & GENMASK_ULL(39, 0)) << 12) | \ + /* GHCBData[11:0] */ \ + GHCB_MSR_PSC_REQ) + +#define GHCB_MSR_PSC_RESP 0x015 +#define GHCB_MSR_PSC_RESP_VAL (val) \ +/* GHCBData[63:32] */ \ + (((u64)(val) & GENMASK_ULL(63, 32)) >> 32) +/* GHCB Hypervisor Feature Request/Response */ #define GHCB_MSR_HV_FT_REQ 0x080#define GHCB_MSR_HV_FT_RESP 0x081
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed: Add helper for validating pages in the decompression stage
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 4f9c403e44e5e88feb27d5e617d1adc9cc7ef684 Gitweb: https://git.kernel.org/tip/4f9c403e44e5e88feb27d5e617d1adc9cc7ef684 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:09 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:10:40 +02:00
x86/compressed: Add helper for validating pages in the decompression stage
Many of the integrity guarantees of SEV-SNP are enforced through the Reverse Map Table (RMP). Each RMP entry contains the GPA at which a particular page of DRAM should be mapped. The VMs can request the hypervisor to add pages in the RMP table via the Page State Change VMGEXIT defined in the GHCB specification.
Inside each RMP entry is a Validated flag; this flag is automatically cleared to 0 by the CPU hardware when a new RMP entry is created for a guest. Each VM page can be either validated or invalidated, as indicated by the Validated flag in the RMP entry. Memory access to a private page that is not validated generates a #VC. A VM must use the PVALIDATE instruction to validate a private page before using it.
To maintain the security guarantee of SEV-SNP guests, when transitioning pages from private to shared, the guest must invalidate the pages before asking the hypervisor to change the page state to shared in the RMP table.
After the pages are mapped private in the page table, the guest must issue a page state change VMGEXIT to mark the pages private in the RMP table and validate them.
Upon boot, BIOS should have validated the entire system memory. During the kernel decompression stage, early_setup_ghcb() uses set_page_decrypted() to make the GHCB page shared (i.e. clear encryption attribute). And while exiting from the decompression, it calls set_page_encrypted() to make the page private.
Add snp_set_page_{private,shared}() helpers that are used by set_page_{decrypted,encrypted}() to change the page state in the RMP table.
[ bp: Massage commit message and comments. ]
--- arch/x86/boot/compressed/ident_map_64.c | 18 ++++++++- arch/x86/boot/compressed/misc.h | 4 ++- arch/x86/boot/compressed/sev.c | 46 ++++++++++++++++++++++++- arch/x86/include/asm/sev-common.h | 26 ++++++++++++++- 4 files changed, 93 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/ident_map_64.c +17 -1
@@ -275,15 +275,31 @@ static int set_clr_page_flags(struct x86_mapping_info *info,* Changing encryption attributes of a page requires to flush it from * the caches. */ -if ((set | clr) & _PAGE_ENC) +if ((set | clr) & _PAGE_ENC) {clflush_page (address); +/* +* If the encryption attribute is being cleared, change the page state +* to shared in the RMP table. +*/ +if (clr) +snp_set_page_shared (__pa (address &PAGE_MASK )); + } +/* Update PTE */ pte = *ptep; pte =pte_set_flags (pte, set); pte =pte_clear_flags (pte, clr);set_pte (ptep, pte); +/* +* If the encryption attribute is being set, then change the page state to +* private in the RMP entry. The page state change must be done after the PTE +* is updated. +*/ +if (set & _PAGE_ENC) +snp_set_page_private (__pa (address &PAGE_MASK )); +/* Flush TLB after changing encryption attribute */ write_cr3 (top_level_pgt);
arch/x86/boot/compressed/misc.h +4 -0
@@ -124,6 +124,8 @@ static inline void console_init(void)void sev_enable (struct boot_params *bp);void sev_es_shutdown_ghcb (void );extern bool sev_es_check_ghcb_fault (unsigned long address); +void snp_set_page_private (unsigned long paddr); +void snp_set_page_shared (unsigned long paddr);#else static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }
@@ -131,6 +133,8 @@ static inline bool sev_es_check_ghcb_fault(unsigned long address) {return false; } +static inline void snp_set_page_private (unsigned long paddr) { } +static inline void snp_set_page_shared (unsigned long paddr) { }#endif /* acpi.c */
arch/x86/boot/compressed/sev.c +46 -0
52 lines not on this page · raw message
arch/x86/include/asm/sev-common.h +26 -0
@@ -57,6 +57,32 @@#define GHCB_MSR_AP_RESET_HOLD_REQ 0x006#define GHCB_MSR_AP_RESET_HOLD_RESP 0x007 +/* +* SNP Page State Change Operation +* +* GHCBData[55:52] - Page operation: +* 0x0001 Page assignment, Private +* 0x0002 Page assignment, Shared +*/ +enum psc_op { +SNP_PAGE_STATE_PRIVATE =1 , +SNP_PAGE_STATE_SHARED , +}; + +#define GHCB_MSR_PSC_REQ 0x014 +#define GHCB_MSR_PSC_REQ_GFN (gfn, op) \ +/* GHCBData[55:52] */ \ + (((u64)((op) & 0xf) << 52) | \ +/* GHCBData[51:12] */ \ + ((u64)((gfn) & GENMASK_ULL(39, 0)) << 12) | \ + /* GHCBData[11:0] */ \ + GHCB_MSR_PSC_REQ) + +#define GHCB_MSR_PSC_RESP 0x015 +#define GHCB_MSR_PSC_RESP_VAL (val) \ +/* GHCBData[63:32] */ \ + (((u64)(val) & GENMASK_ULL(63, 32)) >> 32) +/* GHCB Hypervisor Feature Request/Response */ #define GHCB_MSR_HV_FT_REQ 0x080#define GHCB_MSR_HV_FT_RESP 0x081
PATCH v12 16/46 x86/compressed: Register GHCB memory when SEV-SNP is active
In reply to Brijesh SinghThe SEV-SNP guest is required by the GHCB spec to register the GHCB's Guest Physical Address (GPA). This is because the hypervisor may prefer that a guest use a consistent and/or specific GPA for the GHCB associated with a vCPU. For more information, see the GHCB specification section "GHCB GPA Registration".
If hypervisor can not work with the guest provided GPA then terminate the guest boot.
--- arch/x86/boot/compressed/sev.c | 4 ++++ arch/x86/include/asm/sev-common.h | 13 +++++++++++++ arch/x86/kernel/sev-shared.c | 16 ++++++++++++++++ 3 files changed, 33 insertions(+)
arch/x86/boot/compressed/sev.c +4 -0
@@ -175,6 +175,10 @@ static bool early_setup_ghcb(void)/* Initialize lookup tables for the instruction decoder */ inat_init_tables (); +/* SNP guest requires the GHCB GPA must be registered */ +if (sev_snp_enabled ()) +snp_register_ghcb_early (__pa (&boot_ghcb_page)); +return true; }
arch/x86/include/asm/sev-common.h +13 -0
@@ -57,6 +57,19 @@#define GHCB_MSR_AP_RESET_HOLD_REQ 0x006#define GHCB_MSR_AP_RESET_HOLD_RESP 0x007 +/* GHCB GPA Register */ +#define GHCB_MSR_REG_GPA_REQ 0x012 +#define GHCB_MSR_REG_GPA_REQ_VAL(v) \ + /* GHCBData[63:12] */ \ + (((u64)((v) & GENMASK_ULL(51, 0)) << 12) | \ + /* GHCBData[11:0] */ \ +GHCB_MSR_REG_GPA_REQ ) + +#define GHCB_MSR_REG_GPA_RESP 0x013 +#define GHCB_MSR_REG_GPA_RESP_VAL (v) \ +/* GHCBData[63:12] */ \ + (((u64)(v) & GENMASK_ULL(63, 12)) >> 12) +/* * SNP Page State Change Operation *
arch/x86/kernel/sev-shared.c +16 -0
@@ -68,6 +68,22 @@ static u64 get_hv_features(void)return GHCB_MSR_HV_FT_RESP_VAL (val); } +static void __maybe_unused snp_register_ghcb_early (unsigned long paddr) +{ +unsigned long pfn = paddr >>PAGE_SHIFT ; +u64 val; + +sev_es_wr_ghcb_msr (GHCB_MSR_REG_GPA_REQ_VAL (pfn)); +VMGEXIT (); + + val =sev_es_rd_ghcb_msr (); + +/* If the response GPA is not ours then abort the guest */ +if ((GHCB_RESP_CODE (val) !=GHCB_MSR_REG_GPA_RESP ) || + (GHCB_MSR_REG_GPA_RESP_VAL (val) != pfn)) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_REGISTER ); +} +static bool sev_es_negotiate_protocol (void ) {u64 val;
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed: Register GHCB memory when SEV-SNP is active
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 87294bdb7b4b73555b0fba45da1cdecdc6a0d5a8 Gitweb: https://git.kernel.org/tip/87294bdb7b4b73555b0fba45da1cdecdc6a0d5a8 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:10 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:14:24 +02:00
x86/compressed: Register GHCB memory when SEV-SNP is active
The SEV-SNP guest is required by the GHCB spec to register the GHCB's Guest Physical Address (GPA). This is because the hypervisor may prefer that a guest use a consistent and/or specific GPA for the GHCB associated with a vCPU. For more information, see the GHCB specification section "GHCB GPA Registration".
If hypervisor can not work with the guest provided GPA then terminate the guest boot.
--- arch/x86/boot/compressed/sev.c | 4 ++++ arch/x86/include/asm/sev-common.h | 13 +++++++++++++ arch/x86/kernel/sev-shared.c | 16 ++++++++++++++++ 3 files changed, 33 insertions(+)
arch/x86/boot/compressed/sev.c +4 -0
@@ -175,6 +175,10 @@ static bool early_setup_ghcb(void)/* Initialize lookup tables for the instruction decoder */ inat_init_tables (); +/* SNP guest requires the GHCB GPA must be registered */ +if (sev_snp_enabled ()) +snp_register_ghcb_early (__pa (&boot_ghcb_page)); +return true; }
arch/x86/include/asm/sev-common.h +13 -0
@@ -57,6 +57,19 @@#define GHCB_MSR_AP_RESET_HOLD_REQ 0x006#define GHCB_MSR_AP_RESET_HOLD_RESP 0x007 +/* GHCB GPA Register */ +#define GHCB_MSR_REG_GPA_REQ 0x012 +#define GHCB_MSR_REG_GPA_REQ_VAL(v) \ + /* GHCBData[63:12] */ \ + (((u64)((v) & GENMASK_ULL(51, 0)) << 12) | \ + /* GHCBData[11:0] */ \ +GHCB_MSR_REG_GPA_REQ ) + +#define GHCB_MSR_REG_GPA_RESP 0x013 +#define GHCB_MSR_REG_GPA_RESP_VAL (v) \ +/* GHCBData[63:12] */ \ + (((u64)(v) & GENMASK_ULL(63, 12)) >> 12) +/* * SNP Page State Change Operation *
arch/x86/kernel/sev-shared.c +16 -0
@@ -68,6 +68,22 @@ static u64 get_hv_features(void)return GHCB_MSR_HV_FT_RESP_VAL (val); } +static void __maybe_unused snp_register_ghcb_early (unsigned long paddr) +{ +unsigned long pfn = paddr >>PAGE_SHIFT ; +u64 val; + +sev_es_wr_ghcb_msr (GHCB_MSR_REG_GPA_REQ_VAL (pfn)); +VMGEXIT (); + + val =sev_es_rd_ghcb_msr (); + +/* If the response GPA is not ours then abort the guest */ +if ((GHCB_RESP_CODE (val) !=GHCB_MSR_REG_GPA_RESP ) || + (GHCB_MSR_REG_GPA_RESP_VAL (val) != pfn)) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_REGISTER ); +} +static bool sev_es_negotiate_protocol (void ) {u64 val;
PATCH v12 17/46 x86/sev: Register GHCB memory when SEV-SNP is active
In reply to Brijesh SinghThe SEV-SNP guest is required by the GHCB spec to register the GHCB's Guest Physical Address (GPA). This is because the hypervisor may prefer that a guest use a consistent and/or specific GPA for the GHCB associated with a vCPU. For more information, see the GHCB specification section "GHCB GPA Registration".
--- arch/x86/include/asm/sev.h | 2 ++ arch/x86/kernel/cpu/common.c | 4 +++ arch/x86/kernel/head64.c | 4 ++- arch/x86/kernel/sev-shared.c | 2 +- arch/x86/kernel/sev.c | 47 +++++++++++++++++++++++++++--------- 5 files changed, 45 insertions(+), 14 deletions(-)
arch/x86/include/asm/sev.h +2 -0
@@ -122,6 +122,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) return rc; } +void setup_ghcb (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -130,6 +131,7 @@ static inline void sev_es_nmi_complete(void) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; } +static inline void setup_ghcb (void ) { }#endif #endif
arch/x86/kernel/cpu/common.c +4 -0
@@ -59,6 +59,7 @@#include <asm/cpu_device_id.h> #include <asm/uv/uv.h> #include <asm/sigframe.h> +#include <asm/sev.h> #include "cpu.h"
@@ -2067,6 +2068,9 @@ void cpu_init_exception_handling(void)load_TR_desc (); +/* GHCB need to be setup to handle #VC. */ +setup_ghcb (); +/* Finally load the IDT */ load_current_idt (); }
arch/x86/kernel/head64.c +3 -1
@@ -597,8 +597,10 @@ static void startup_64_load_idt(unsigned long physbase)void early_setup_idt (void ) {/* VMM Communication Exception */ -if (IS_ENABLED (CONFIG_AMD_MEM_ENCRYPT )) +if (IS_ENABLED (CONFIG_AMD_MEM_ENCRYPT )) { +setup_ghcb ();set_bringup_idt_handler (bringup_idt_table,X86_TRAP_VC , vc_boot_ghcb); + } bringup_idt_descr.address = (unsigned long )bringup_idt_table;native_load_idt (&bringup_idt_descr);
arch/x86/kernel/sev-shared.c +1 -1
@@ -68,7 +68,7 @@ static u64 get_hv_features(void)return GHCB_MSR_HV_FT_RESP_VAL (val); } -static void __maybe_unused snp_register_ghcb_early (unsigned long paddr) +static void snp_register_ghcb_early (unsigned long paddr) {unsigned long pfn = paddr >>PAGE_SHIFT ;u64 val;
arch/x86/kernel/sev.c +35 -12
74 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Register GHCB memory when SEV-SNP is active
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 95d33bfaa3e169cfec1926e0d0f0c6b0ea75d763 Gitweb: https://git.kernel.org/tip/95d33bfaa3e169cfec1926e0d0f0c6b0ea75d763 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:11 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:16:58 +02:00
x86/sev: Register GHCB memory when SEV-SNP is active
The SEV-SNP guest is required by the GHCB spec to register the GHCB's Guest Physical Address (GPA). This is because the hypervisor may prefer that a guest uses a consistent and/or specific GPA for the GHCB associated with a vCPU. For more information, see the GHCB specification section "GHCB GPA Registration".
[ bp: Cleanup comments. ]
--- arch/x86/include/asm/sev.h | 2 ++- arch/x86/kernel/cpu/common.c | 4 +++- arch/x86/kernel/head64.c | 4 ++- arch/x86/kernel/sev-shared.c | 2 +- arch/x86/kernel/sev.c | 46 +++++++++++++++++++++++++---------- 5 files changed, 44 insertions(+), 14 deletions(-)
arch/x86/include/asm/sev.h +2 -0
@@ -122,6 +122,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) return rc; } +void setup_ghcb (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -130,6 +131,7 @@ static inline void sev_es_nmi_complete(void) { }static inline int sev_es_efi_map_ghcbs (pgd_t *pgd) {return 0 ; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; } +static inline void setup_ghcb (void ) { }#endif #endif
arch/x86/kernel/cpu/common.c +4 -0
@@ -60,6 +60,7 @@#include <asm/uv/uv.h> #include <asm/sigframe.h> #include <asm/traps.h> +#include <asm/sev.h> #include "cpu.h"
@@ -2124,6 +2125,9 @@ void cpu_init_exception_handling(void)load_TR_desc (); +/* GHCB needs to be setup to handle #VC. */ +setup_ghcb (); +/* Finally load the IDT */ load_current_idt (); }
arch/x86/kernel/head64.c +3 -1
@@ -597,8 +597,10 @@ static void startup_64_load_idt(unsigned long physbase)void early_setup_idt (void ) {/* VMM Communication Exception */ -if (IS_ENABLED (CONFIG_AMD_MEM_ENCRYPT )) +if (IS_ENABLED (CONFIG_AMD_MEM_ENCRYPT )) { +setup_ghcb ();set_bringup_idt_handler (bringup_idt_table,X86_TRAP_VC , vc_boot_ghcb); + } bringup_idt_descr.address = (unsigned long )bringup_idt_table;native_load_idt (&bringup_idt_descr);
arch/x86/kernel/sev-shared.c +1 -1
@@ -68,7 +68,7 @@ static u64 get_hv_features(void)return GHCB_MSR_HV_FT_RESP_VAL (val); } -static void __maybe_unused snp_register_ghcb_early (unsigned long paddr) +static void snp_register_ghcb_early (unsigned long paddr) {unsigned long pfn = paddr >>PAGE_SHIFT ;u64 val;
arch/x86/kernel/sev.c +34 -12
73 lines not on this page · raw message
PATCH v12 18/46 x86/sev: Add helper for validating pages in early enc attribute changes
In reply to Brijesh SinghThe early_set_memory_{encrypted,decrypted}() are used for changing the page from decrypted (shared) to encrypted (private) and vice versa. When SEV-SNP is active, the page state transition needs to go through additional steps.
If the page is transitioned from shared to private, then perform the following after the encryption attribute is set in the page table:
1. Issue the page state change VMGEXIT to add the page as a private in the RMP table.
2. Validate the page after its successfully added in the RMP table.
To maintain the security guarantees, if the page is transitioned from private to shared, then perform the following before clearing the encryption attribute from the page table.
1. Invalidate the page.
2. Issue the page state change VMGEXIT to make the page shared in the RMP table.
The early_set_memory_{encrypted,decrypted} can be called before the GHCB is setup, use the SNP page state MSR protocol VMGEXIT defined in the GHCB specification to request the page state change in the RMP table.
While at it, add a helper snp_prep_memory() which will be used in probe_roms(), in a later patch.
--- arch/x86/include/asm/sev.h | 10 ++++ arch/x86/kernel/sev.c | 99 +++++++++++++++++++++++++++++++++++ arch/x86/mm/mem_encrypt_amd.c | 58 ++++++++++++++++++-- 3 files changed, 163 insertions(+), 4 deletions(-)
arch/x86/include/asm/sev.h +10 -0
@@ -123,6 +123,11 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) return rc; }void setup_ghcb (void ); +void __init early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr, +unsigned int npages); +void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, +unsigned int npages); +void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -132,6 +137,11 @@ static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; }static inline void setup_ghcb (void ) { } +static inline void __init +early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr,unsigned int npages) { } +static inline void __init +early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { } +static inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { }#endif #endif
arch/x86/kernel/sev.c +99 -0
105 lines not on this page · raw message
arch/x86/mm/mem_encrypt_amd.c +54 -4
88 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Add helper for validating pages in early enc attribute changes
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 5e5ccff60a2977142d39b987a8b90e422d9fc634 Gitweb: https://git.kernel.org/tip/5e5ccff60a2977142d39b987a8b90e422d9fc634 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:12 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:22:54 +02:00
x86/sev: Add helper for validating pages in early enc attribute changes
early_set_memory_{encrypted,decrypted}() are used for changing the page state from decrypted (shared) to encrypted (private) and vice versa.
When SEV-SNP is active, the page state transition needs to go through additional steps.
If the page is transitioned from shared to private, then perform the following after the encryption attribute is set in the page table:
1. Issue the page state change VMGEXIT to add the page as a private in the RMP table.
2. Validate the page after its successfully added in the RMP table.
To maintain the security guarantees, if the page is transitioned from private to shared, then perform the following before clearing the encryption attribute from the page table.
1. Invalidate the page.
2. Issue the page state change VMGEXIT to make the page shared in the RMP table.
early_set_memory_{encrypted,decrypted}() can be called before the GHCB is setup so use the SNP page state MSR protocol VMGEXIT defined in the GHCB specification to request the page state change in the RMP table.
While at it, add a helper snp_prep_memory() which will be used in probe_roms(), in a later patch.
[ bp: Massage commit message. ]
--- arch/x86/include/asm/sev.h | 10 +++- arch/x86/kernel/sev.c | 99 +++++++++++++++++++++++++++++++++- arch/x86/mm/mem_encrypt_amd.c | 58 +++++++++++++++++-- 3 files changed, 163 insertions(+), 4 deletions(-)
arch/x86/include/asm/sev.h +10 -0
@@ -123,6 +123,11 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) return rc; }void setup_ghcb (void ); +void __init early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr, +unsigned int npages); +void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, +unsigned int npages); +void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -132,6 +137,11 @@ static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }static inline int pvalidate (unsigned long vaddr,bool rmp_psize,bool validate) {return 0 ; }static inline int rmpadjust (unsigned long vaddr,bool rmp_psize,unsigned long attrs) {return 0 ; }static inline void setup_ghcb (void ) { } +static inline void __init +early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr,unsigned int npages) { } +static inline void __init +early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { } +static inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { }#endif #endif
arch/x86/kernel/sev.c +99 -0
105 lines not on this page · raw message
arch/x86/mm/mem_encrypt_amd.c +54 -4
88 lines not on this page · raw message
PATCH v12 19/46 x86/kernel: Make the .bss..decrypted section shared in RMP table
In reply to Brijesh SinghThe encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/x86/kernel/head64.c +13 -0
@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* +* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD ); + i =pmd_index (vaddr); pmd[i] -=sme_get_me_mask (); }
Signature · 1 line
2.25.1
[tip: x86/sev] x86/kernel: Mark the .bss..decrypted section as shared in the RMP table
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: efac0eedfab515e523cde5cb7a62289eb2ee58f8 Gitweb: https://git.kernel.org/tip/efac0eedfab515e523cde5cb7a62289eb2ee58f8 Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:13 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:23:00 +02:00
x86/kernel: Mark the .bss..decrypted section as shared in the RMP table
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state needs to be updated in the RMP table.
--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/x86/kernel/head64.c +13 -0
@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* +* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD ); + i =pmd_index (vaddr); pmd[i] -=sme_get_me_mask (); }
Sean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
In reply to Brijesh Singhs/Brijesh/Michael
Quoted 24 lines · Brijesh Singh
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/x86/kernel/head64.c +2
-0@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/*
arch/x86/kernel/head64.c static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv · line 158
Quoted 10 lines
arch/x86/kernel/head64.c +10
-0+* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD );
This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to early_snp_set_memory_shared() if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.
Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because INIT_EX is also broken.
The crash incurs a very, very slow reboot, and I was out of cycles to work on this about three hours ago. If someone on the AMD side can repro, it would be much appreciated.
Sean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 44 lines · Sean Christopherson
s/Brijesh/Michael
Quoted 24 lines · Brijesh Singh
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/x86/kernel/head64.c +2
-0@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* arch/x86/kernel/head64.c static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv · line 158
Quoted 10 lines
arch/x86/kernel/head64.c +10
-0+* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD );This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
Quoted 7 lines
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.
The SEV INIT_EX was a PEBKAC issue. An SEV guest boots just fine with a clang-built kernel, so either it's a finnicky relocation issue or something specific to SME.
Quoted 3 lines
The crash incurs a very, very slow reboot, and I was out of cycles to work on this about three hours ago. If someone on the AMD side can repro, it would be much appreciated.
Tom Lendacky
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 50 lines · Sean Christopherson
Quoted 49 lines · Sean Christopherson
s/Brijesh/Michael
Quoted 24 lines · Brijesh Singh
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/x86/kernel/head64.c +2
-0@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* arch/x86/kernel/head64.c static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv · line 158
Quoted 10 lines
arch/x86/kernel/head64.c +10
-0+* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD );This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.
Quoted 5 lines
Quoted 2 lines
Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.The SEV
INIT_EXwas a PEBKAC issue. An SEV guest boots just fine with a clang-built kernel, so either it's a finnicky relocation issue or something specific to SME.
I just built and booted 5.19-rc2 with clang-13 and SME enabled without issue:
[ 4.118226] Memory Encryption Features active: AMD SME
Maybe something with your kernel config? Can you send me your config?
Thanks,
Tom
Quoted 4 lines
Quoted 4 lines
The crash incurs a very, very slow reboot, and I was out of cycles to work on this about three hours ago. If someone on the AMD side can repro, it would be much appreciated.
Sean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 54 lines · Tom Lendacky
Quoted 53 lines · Sean Christopherson
Quoted 51 lines · Sean Christopherson
s/Brijesh/Michael
Quoted 24 lines · Brijesh Singh
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/x86/kernel/head64.c +2
-0@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* arch/x86/kernel/head64.c static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv · line 158
Quoted 10 lines
arch/x86/kernel/head64.c +10
-0+* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD );This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.
Quoted 6 lines
Quoted 2 lines
The SEV
INIT_EXwas a PEBKAC issue. An SEV guest boots just fine with a clang-built kernel, so either it's a finnicky relocation issue or something specific to SME.I just built and booted 5.19-rc2 with clang-13 and SME enabled without issue:
[ 4.118226] Memory Encryption Features active: AMD SME
Phooey.
Quoted 1 line
Maybe something with your kernel config? Can you send me your config?
Attached. If you can't repro, I'll find someone on our end to work on this.
Thanks!
Tom Lendacky
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 60 lines · Sean Christopherson
Quoted 59 lines · Tom Lendacky
Quoted 50 lines · Sean Christopherson
Quoted 49 lines · Sean Christopherson
s/Brijesh/Michael
Quoted 24 lines · Brijesh Singh
The encryption attribute for the .bss..decrypted section is cleared in the initial page table build. This is because the section contains the data that need to be shared between the guest and the hypervisor.
When SEV-SNP is active, just clearing the encryption attribute in the page table is not enough. The page state need to be updated in the RMP table.
Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/kernel/head64.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)arch/x86/kernel/head64.c +2
-0@@ -143,7 +143,20 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdvif (sme_get_me_mask ()) { vaddr = (unsigned long )__start_bss_decrypted; vaddr_end = (unsigned long )__end_bss_decrypted; +for (; vaddr < vaddr_end; vaddr +=PMD_SIZE ) { +/* arch/x86/kernel/head64.c static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv · line 158
Quoted 10 lines
arch/x86/kernel/head64.c +10
-0+* On SNP, transition the page to shared in the RMP table so that +* it is consistent with the page table attribute change. +* +* __start_bss_decrypted has a virtual address in the high range +* mapping (kernel .text). PVALIDATE, by way of +* early_snp_set_memory_shared(), requires a valid virtual +* address but the kernel is currently running off of the identity +* mapping so use __pa() to get a *currently* valid virtual address. +*/ +early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD );This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Quoted 5 lines
Quoted 2 lines
Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.The SEV
INIT_EXwas a PEBKAC issue. An SEV guest boots just fine with a clang-built kernel, so either it's a finnicky relocation issue or something specific to SME.I just built and booted 5.19-rc2 with clang-13 and SME enabled without issue:
Quoted 7 lines
Quoted 1 line
[ 4.118226] Memory Encryption Features active: AMD SMEPhooey.
Quoted 1 line
Maybe something with your kernel config? Can you send me your config?
Attached. If you can't repro, I'll find someone on our end to work on this.
I was able to repro. It dies in the cc_platform_has() code, where it is trying to do an indirect jump based on the attribute (actually in the amd_cc_platform_has() which I think has been optimized in):
bool cc_platform_has(enum cc_attr attr)
{
ffffffff81002140: 55 push %rbp
ffffffff81002141: 48 89 e5 mov %rsp,%rbp
switch (vendor) {
ffffffff81002144: 8b 05 c6 e9 3a 01 mov 0x13ae9c6(%rip),%eax # ffffffff823b0b10 <vendor>
ffffffff8100214a: 83 f8 03 cmp $0x3,%eax
ffffffff8100214d: 74 25 je ffffffff81002174 <cc_platform_has+0x34>
ffffffff8100214f: 83 f8 02 cmp $0x2,%eax
ffffffff81002152: 74 2f je ffffffff81002183 <cc_platform_has+0x43>
ffffffff81002154: 83 f8 01 cmp $0x1,%eax
ffffffff81002157: 75 26 jne ffffffff8100217f <cc_platform_has+0x3f>
switch (attr) {
ffffffff81002159: 83 ff 05 cmp $0x5,%edi
ffffffff8100215c: 77 21 ja ffffffff8100217f <cc_platform_has+0x3f>
ffffffff8100215e: 89 f8 mov %edi,%eax
ffffffff81002160: ff 24 c5 c0 01 00 82 jmp *-0x7dfffe40(,%rax,8)This last line is what causes the reset. I'm guessing that the jump isn't valid at this point because we are running in identity mapped mode and not with a kernel virtual address at this point.
Trying to see what the difference was between your config and mine, the indirect jump lead me to check the setting of CONFIG_RETPOLINE. Your config did not have it enabled, so I set CONFIG_RETPOLINE=y, and with that, the kernel boots successfully. With retpolines, the code is completely different around here:
bool cc_platform_has(enum cc_attr attr)
{
ffffffff81001f30: 55 push %rbp
ffffffff81001f31: 48 89 e5 mov %rsp,%rbp
switch (vendor) {
ffffffff81001f34: 8b 05 26 8f 37 01 mov 0x1378f26(%rip),%eax # ffffffff8237ae60 <vendor>
ffffffff81001f3a: 83 f8 03 cmp $0x3,%eax
ffffffff81001f3d: 74 29 je ffffffff81001f68 <cc_platform_has+0x38>
ffffffff81001f3f: 83 f8 02 cmp $0x2,%eax
ffffffff81001f42: 74 33 je ffffffff81001f77 <cc_platform_has+0x47>
ffffffff81001f44: 83 f8 01 cmp $0x1,%eax
ffffffff81001f47: 75 2a jne ffffffff81001f73 <cc_platform_has+0x43>
ffffffff81001f49: 31 c0 xor %eax,%eax
switch (attr) {
ffffffff81001f4b: 83 ff 02 cmp $0x2,%edi
ffffffff81001f4e: 7f 2f jg ffffffff81001f7f <cc_platform_has+0x4f>
ffffffff81001f50: 85 ff test %edi,%edi
ffffffff81001f52: 74 47 je ffffffff81001f9b <cc_platform_has+0x6b>
ffffffff81001f54: 83 ff 01 cmp $0x1,%edi
ffffffff81001f57: 74 5b je ffffffff81001fb4 <cc_platform_has+0x84>
ffffffff81001f59: 83 ff 02 cmp $0x2,%edi
ffffffff81001f5c: 75 08 jne ffffffff81001f66 <cc_platform_has+0x36>
return sev_status & MSR_AMD64_SEV_ENABLED;
ffffffff81001f5e: 8a 05 44 3f 64 01 mov 0x1643f44(%rip),%al # ffffffff82645ea8 <sev_status>
ffffffff81001f64: 24 01 and $0x1,%al
case CC_VENDOR_HYPERV:
return hyperv_cc_platform_has(attr);
default:
return false;
}
}
ffffffff81001f66: 5d pop %rbp
ffffffff81001f67: c3 ret
switch (attr) {
ffffffff81001f68: 83 ff 07 cmp $0x7,%edi
ffffffff81001f6b: 73 06 jae ffffffff81001f73 <cc_platform_has+0x43>
ffffffff81001f6d: 40 f6 c7 01 test $0x1,%dil
ffffffff81001f71: eb 07 jmp ffffffff81001f7a <cc_platform_has+0x4a>
ffffffff81001f73: 31 c0 xor %eax,%eax
}
ffffffff81001f75: 5d pop %rbp
ffffffff81001f76: c3 ret
return attr == CC_ATTR_GUEST_MEM_ENCRYPT;
ffffffff81001f77: 83 ff 02 cmp $0x2,%edi
ffffffff81001f7a: 0f 94 c0 sete %al
}
ffffffff81001f7d: 5d pop %rbp
ffffffff81001f7e: c3 ret
switch (attr) {.
.
.
I'm not sure if there's a way to remove the jump table optimization for the arch/x86/coco/core.c file when retpolines aren't configured.
Thanks,
Tom
Quoted 2 lines
Thanks!
Sean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 33 lines · Tom Lendacky
Quoted 19 lines · Sean Christopherson
Quoted 19 lines
Quoted 11 lines
Quoted 11 lines
This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Quoted 5 lines
Quoted 2 lines
Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.The SEV
INIT_EXwas a PEBKAC issue. An SEV guest boots just fine with a clang-built kernel, so either it's a finnicky relocation issue or something specific to SME.I just built and booted 5.19-rc2 with clang-13 and SME enabled without issue:
Quoted 7 lines
Quoted 1 line
[ 4.118226] Memory Encryption Features active: AMD SMEPhooey.
Quoted 1 line
Maybe something with your kernel config? Can you send me your config?
Attached. If you can't repro, I'll find someone on our end to work on this.
I was able to repro. It dies in the
cc_platform_has()code, where it is trying to do an indirect jump based on the attribute (actually in theamd_cc_platform_has()which I think has been optimized in):bool
cc_platform_has(enum cc_attr attr)
...
Quoted 10 lines
ffffffff81002160: ff 24 c5 c0 01 00 82 jmp *-0x7dfffe40(,%rax,8)This last line is what causes the reset. I'm guessing that the jump isn't valid at this point because we are running in identity mapped mode and not with a kernel virtual address at this point.
Trying to see what the difference was between your config and mine, the indirect jump lead me to check the setting of
CONFIG_RETPOLINE. Your config did not have it enabled, so I setCONFIG_RETPOLINE=y, and with that, the kernel boots successfully.
That would explain why my VMs didn't fail, I build those kernels with CONFIG_RETPOLINE=y.
Quoted 1 line
With retpolines, the code is completely different around here:
...
Quoted 2 lines
I'm not sure if there's a way to remove the jump table optimization for the
arch/x86/coco/core.cfile when retpolines aren't configured.
And for post-boot I don't think we'd want to disable any such optimizations.
A possibled "fix" would be to do what sme_encrypt_kernel() does and just query sev_status directly. But even that works, the fragility of the boot code is terrifying :-( I can't think of any clever solutions though.
Many thanks again Tom!
--- arch/x86/include/asm/sev.h | 4 ++++ arch/x86/kernel/head64.c | 10 +++++++--- arch/x86/kernel/sev.c | 16 +++++++++++----- 3 files changed, 22 insertions(+), 8 deletions(-)
arch/x86/include/asm/sev.h +4 -0
@@ -193,6 +193,8 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)void setup_ghcb (void );void __init early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr,unsigned int npages); +void __init __early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, +unsigned int npages);void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages);void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op);
@@ -214,6 +216,8 @@ static inline void setup_ghcb(void) { }static inline void __init early_snp_set_memory_private (unsigned long vaddr,unsigned long paddr,unsigned int npages) { }static inline void __init +__early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { } +static inline void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { }static inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { }static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { }
arch/x86/kernel/head64.c +7 -3
@@ -127,7 +127,9 @@ static bool __head check_la57_support(unsigned long physaddr) }#endif -static unsigned long __head sme_postprocess_startup (struct boot_params *bp,pmdval_t *pmd) +static unsigned long __head sme_postprocess_startup (struct boot_params *bp, +pmdval_t *pmd, +unsigned long physaddr) {unsigned long vaddr, vaddr_end;int i;
@@ -156,7 +158,9 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv* address but the kernel is currently running off of the identity * mapping so use __pa() to get a *currently* valid virtual address. */ -early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD ); +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED_BIT ) +__early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr), +PTRS_PER_PMD ); i =pmd_index (vaddr); pmd[i] -=sme_get_me_mask ();
@@ -316,7 +320,7 @@ unsigned long __head __startup_64(unsigned long physaddr,*/ *fixup_long (&phys_base, physaddr) += load_delta -sme_get_me_mask (); -return sme_postprocess_startup (bp, pmd); +return sme_postprocess_startup (bp, pmd, physaddr); }/* Wipe all early page tables except for the kernel symbol map */
arch/x86/kernel/sev.c +11 -5
@@ -714,12 +714,9 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddpvalidate_pages (vaddr, npages, true); } -void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, -unsigned int npages) +void __init __early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, +unsigned int npages) { -if (!cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) -return ; -/* Invalidate the memory pages before they are marked shared in the RMP table. */ pvalidate_pages (vaddr, npages, false);
@@ -727,6 +724,15 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddrearly_set_pages_state (paddr, npages,SNP_PAGE_STATE_SHARED ); } +void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr, +unsigned int npages) +{ +if (!cc_platform_has (CC_ATTR_GUEST_SEV_SNP )) +return ; + +__early_snp_set_memory_shared (vaddr, paddr, npages); +} +void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) {unsigned long vaddr, npages;
base-commit: b13baccc3850ca8b8cccbf8ed9912dbaa0fdf7f3 --
Tom Lendacky
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 18 lines · Sean Christopherson
Quoted 15 lines · Tom Lendacky
Quoted 14 lines · Sean Christopherson
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.
Quoted 8 lines
Quoted 2 lines
I'm not sure if there's a way to remove the jump table optimization for the
arch/x86/coco/core.cfile when retpolines aren't configured.And for post-boot I don't think we'd want to disable any such optimizations.
A possibled "fix" would be to do what
sme_encrypt_kernel()does and just querysev_statusdirectly. But even that works, the fragility of the boot code is terrifying :-( I can't think of any clever solutions though.
I worry that another use of cc_platform_has() could creep in at some point and cause the same issue. Not sure how bad it would be, performance-wise, to remove the jump table optimization for arch/x86/coco/core.c.
I guess we can wait for Boris to get back and chime in.
arch/x86/kernel/head64.c static bool __head check_la57_support(unsigned long physaddr) · line 132
Quoted 12 lines
arch/x86/kernel/head64.c +3
-1@@ -127,7 +127,9 @@ static bool __head check_la57_support(unsigned long physaddr) }#endif -static unsigned long __head sme_postprocess_startup (struct boot_params *bp,pmdval_t *pmd) +static unsigned long __head sme_postprocess_startup (struct boot_params *bp, +pmdval_t *pmd, +unsigned long physaddr)
I noticed that you added the physaddr parameter but never use it...
Thanks,
Tom
Quoted 23 lines
arch/x86/kernel/head64.c +4
-2{unsigned long vaddr, vaddr_end;int i;@@ -156,7 +158,9 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv* address but the kernel is currently running off of the identity * mapping so use __pa() to get a *currently* valid virtual address. */ -early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr),PTRS_PER_PMD ); +if (sev_status &MSR_AMD64_SEV_SNP_ENABLED_BIT ) +__early_snp_set_memory_shared (__pa (vaddr),__pa (vaddr), +PTRS_PER_PMD ); i =pmd_index (vaddr); pmd[i] -=sme_get_me_mask ();@@ -316,7 +320,7 @@ unsigned long __head __startup_64(unsigned long physaddr,*/ *fixup_long (&phys_base, physaddr) += load_delta -sme_get_me_mask (); -return sme_postprocess_startup (bp, pmd); +return sme_postprocess_startup (bp, pmd, physaddr); }/* Wipe all early page tables except for the kernel symbol map */
Sean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 24 lines · Tom Lendacky
Quoted 23 lines · Sean Christopherson
Quoted 12 lines · Tom Lendacky
Quoted 11 lines · Sean Christopherson
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
This breaks SME on Rome and Milan when compiling with clang-13. I haven't been able to figure out exactly what goes wrong. printk isn't functional at this point, and interactive debug during boot on our test systems is beyond me. I can't even verify that the bug is specific to clang because the draconian build system for our test systems apparently is stuck pointing at gcc-4.9.
I suspect the issue is related to relocation and/or encrypting memory, as skipping the call to
early_snp_set_memory_shared()if SNP isn't active masks the issue. I've dug through the assembly and haven't spotted a smoking gun, e.g. no obvious use of absolute addresses.Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
Forcing a VM through the same path doesn't fail. I can't test an SEV guest at the moment because
INIT_EXis also broken.I'm not sure if there's a way to remove the jump table optimization for the
arch/x86/coco/core.cfile when retpolines aren't configured.And for post-boot I don't think we'd want to disable any such optimizations.
Quoted 7 lines
Quoted 3 lines
A possibled "fix" would be to do what
sme_encrypt_kernel()does and just querysev_statusdirectly. But even that works, the fragility of the boot code is terrifying :-( I can't think of any clever solutions though.I worry that another use of
cc_platform_has()could creep in at some point and cause the same issue. Not sure how bad it would be, performance-wise, to remove the jump table optimization forarch/x86/coco/core.c.
One thought would be to initialize "vendor" to a bogus value, disallow calls to cc_set_vendor() until after the kernel as gotten to a safe point, and then WARN (or panic?) if cc_platform_has() is called before "vendor" is explicitly set. New calls can still get in, but they'll be much easier to detect and less likely to escape initial testing.
arch/x86/coco/core.c +8 -1
@@ -13,7 +13,11 @@#include <asm/coco.h> #include <asm/processor.h> -static enum cc_vendor vendor__ro_after_init ; +/* +* Initialize the vendor to garbage to detect usage of cc_platform_has() before +* the vendor has been set. +*/ +static enum cc_vendor vendor =CC_NR_VENDORS __ro_after_init ;static u64 cc_mask__ro_after_init ;static bool intel_cc_platform_has (enum cc_attr attr)
@@ -90,7 +94,10 @@ bool cc_platform_has(enum cc_attr attr)return intel_cc_platform_has (attr);case CC_VENDOR_HYPERV :return hyperv_cc_platform_has (attr); +case CC_VENDOR_NONE : +return false;default : +WARN_ONCE (1 ,"blah blah blah" );return false; } }
arch/x86/include/asm/coco.h +1 -0
@@ -9,6 +9,7 @@ enum cc_vendor {CC_VENDOR_AMD ,CC_VENDOR_HYPERV ,CC_VENDOR_INTEL , + CC_NR_VENDORS, };void cc_set_vendor (enum cc_vendor v);
Quoted 10 lines
I guess we can wait for Boris to get back and chime in.
Quoted 8 lines
arch/x86/kernel/head64.c +0
-0@@ -127,7 +127,9 @@ static bool __head check_la57_support(unsigned long physaddr) }#endif
Quoted 6 lines
arch/x86/kernel/head64.c static bool __head check_la57_support(unsigned long physaddr) · line 132
Quoted 4 lines
arch/x86/kernel/head64.c +3
-1-static unsigned long __head sme_postprocess_startup (struct boot_params *bp,pmdval_t *pmd) +static unsigned long __head sme_postprocess_startup (struct boot_params *bp, +pmdval_t *pmd, +unsigned long physaddr)I noticed that you added the physaddr parameter but never use it...
Likely just garbage on my end, I was trying various ideas.
Borislav Petkov
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 3 lines · Sean Christopherson
Quoted 3 lines
I worry that another use of
cc_platform_has()could creep in at some point and cause the same issue. Not sure how bad it would be, performance-wise, to remove the jump table optimization forarch/x86/coco/core.c.
Is there a gcc switch for that?
Quoted 5 lines
One thought would be to initialize "vendor" to a bogus value, disallow calls to
cc_set_vendor()until after the kernel as gotten to a safe point, and then WARN (or panic?) ifcc_platform_has()is called before "vendor" is explicitly set. New calls can still get in, but they'll be much easier to detect and less likely to escape initial testing.
The invalid vendor thing makes sense but I don't think it'll help in this case.
We set vendor in sme_enable() which comes before the
__startup_64 -> sme_postprocess_startup
path you're hitting.
We could do only the aspect of checking whether it hasn't been set yet and warn then, in order to make the usage more robust...
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteSean Christopherson
maintainerRe: [PATCH v12 19/46] x86/kernel: Make the .bss..decrypted section shared in RMP table
Quoted 6 lines · Borislav Petkov
Quoted 3 lines · Sean Christopherson
Quoted 3 lines
I worry that another use of
cc_platform_has()could creep in at some point and cause the same issue. Not sure how bad it would be, performance-wise, to remove the jump table optimization forarch/x86/coco/core.c.Is there a gcc switch for that?
I believe -fno-jump-tables will do the trick. That also reminds me exactly why CONFIG_RETPOLINE=y isn't broken, jump tables are disabled when retpolines are enabled[*].
[*] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86952
Quoted 6 lines
Quoted 5 lines
One thought would be to initialize "vendor" to a bogus value, disallow calls to
cc_set_vendor()until after the kernel as gotten to a safe point, and then WARN (or panic?) ifcc_platform_has()is called before "vendor" is explicitly set. New calls can still get in, but they'll be much easier to detect and less likely to escape initial testing.
Quoted 8 lines
The invalid vendor thing makes sense but I don't think it'll help in this case.
We set vendor in
sme_enable()which comes before the
__startup_64->sme_postprocess_startuppath you're hitting.
Right, but that's easily solved, no? E.g.
arch/x86/mm/mem_encrypt_amd.c +2 -0
@@ -487,6 +487,8 @@ void __init sme_early_init(void)if (!sme_me_mask)return ; +cc_set_vendor (CC_VENDOR_AMD ); + early_pmd_flags =__sme_set (early_pmd_flags); __supported_pte_mask =__sme_set (__supported_pte_mask);
arch/x86/mm/mem_encrypt_identity.c +0 -1
@@ -611,7 +611,6 @@ void __init sme_enable(struct boot_params *bp) out:if (sme_me_mask) { physical_mask &= ~sme_me_mask; -cc_set_vendor (CC_VENDOR_AMD );cc_set_mask (sme_me_mask); } }
And disallow cc_set_vendor() before x86_64_start_kernel(), then fix any fallout.
Quoted 8 lines
We could do only the aspect of checking whether it hasn't been set yet and warn then, in order to make the usage more robust...
Signature · 4 lines
Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette
PATCH v12 20/46 x86/kernel: Validate ROM memory before accessing when SEV-SNP is active
In reply to Brijesh Singhprobe_roms() accesses the memory range (0xc0000 - 0x10000) to probe various ROMs. The memory range is not part of the E820 system RAM range. The memory range is mapped as private (i.e encrypted) in page table.
When SEV-SNP is active, all the private memory must be validated before the access. The ROM range was not part of E820 map, so the guest BIOS did not validate it. An access to invalidated memory will cause a VC exception. The guest does not support handling not-validated VC exception yet, so validate the ROM memory regions before it is accessed.
--- arch/x86/kernel/probe_roms.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/x86/kernel/probe_roms.c +12 -1
@@ -21,6 +21,7 @@#include <asm/sections.h> #include <asm/io.h> #include <asm/setup_arch.h> +#include <asm/sev.h> static struct resource system_rom_resource = { .name ="System ROM" ,
@@ -197,11 +198,21 @@ static int __init romchecksum(const unsigned char *rom, unsigned long length)void __init probe_roms (void ) { -const unsigned char *rom;unsigned long start, length, upper; +const unsigned char *rom;unsigned char c;int i; +/* +* The ROM memory range is not part of the e820 table and is therefore not +* pre-validated by BIOS. The kernel page table maps the ROM region as encrypted +* memory, and SNP requires encrypted memory to be validated before access. +* Do that here. +*/ +snp_prep_memory (video_rom_resource.start, + ((system_rom_resource.end +1 ) - video_rom_resource.start), +SNP_PAGE_STATE_PRIVATE ); +/* video rom */ upper = adapter_rom_resources[0 ].start;for (start = video_rom_resource.start; start < upper; start +=2048 ) {
Signature · 1 line
2.25.1
[tip: x86/sev] x86/kernel: Validate ROM memory before accessing when SEV-SNP is active
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 9704c07bf9f7682a83aec4e66f2d9154dbd8577f Gitweb: https://git.kernel.org/tip/9704c07bf9f7682a83aec4e66f2d9154dbd8577f Author: Brijesh Singh <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:14 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:23:09 +02:00
x86/kernel: Validate ROM memory before accessing when SEV-SNP is active
probe_roms() accesses the memory range (0xc0000 - 0x10000) to probe various ROMs. The memory range is not part of the E820 system RAM range. The memory range is mapped as private (i.e encrypted) in the page table.
When SEV-SNP is active, all the private memory must be validated before accessing. The ROM range was not part of E820 map, so the guest BIOS did not validate it. An access to invalidated memory will cause a exception yet, so validate the ROM memory regions before it is accessed.
[ bp: Massage commit message. ]
--- arch/x86/kernel/probe_roms.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/x86/kernel/probe_roms.c +12 -1
@@ -21,6 +21,7 @@#include <asm/sections.h> #include <asm/io.h> #include <asm/setup_arch.h> +#include <asm/sev.h> static struct resource system_rom_resource = { .name ="System ROM" ,
@@ -197,11 +198,21 @@ static int __init romchecksum(const unsigned char *rom, unsigned long length)void __init probe_roms (void ) { -const unsigned char *rom;unsigned long start, length, upper; +const unsigned char *rom;unsigned char c;int i; +/* +* The ROM memory range is not part of the e820 table and is therefore not +* pre-validated by BIOS. The kernel page table maps the ROM region as encrypted +* memory, and SNP requires encrypted memory to be validated before access. +* Do that here. +*/ +snp_prep_memory (video_rom_resource.start, + ((system_rom_resource.end +1 ) - video_rom_resource.start), +SNP_PAGE_STATE_PRIVATE ); +/* video rom */ upper = adapter_rom_resources[0 ].start;for (start = video_rom_resource.start; start < upper; start +=2048 ) {
PATCH v12 21/46 x86/mm: Validate memory when changing the C-bit
In reply to Brijesh SinghAdd the needed functionality to change pages state from shared to private and vice-versa using the Page State Change VMGEXIT as documented in the GHCB spec.
--- arch/x86/include/asm/sev-common.h | 22 ++++ arch/x86/include/asm/sev.h | 4 + arch/x86/include/uapi/asm/svm.h | 2 + arch/x86/kernel/sev.c | 168 ++++++++++++++++++++++++++++++ arch/x86/mm/mem_encrypt_amd.c | 13 +++ 5 files changed, 209 insertions(+)
arch/x86/include/asm/sev-common.h +22 -0
@@ -105,6 +105,28 @@ enum psc_op {#define GHCB_HV_FT_SNP BIT_ULL(0) +/* SNP Page State Change NAE event */ +#define VMGEXIT_PSC_MAX_ENTRY 253 + +struct psc_hdr { +u16 cur_entry; +u16 end_entry; +u32 reserved; +} __packed; + +struct psc_entry { +u64 cur_page :12 , + gfn :40 , + operation :4 , + pagesize :1 , + reserved :7 ; +} __packed; + +struct snp_psc_desc { +struct psc_hdr hdr; +struct psc_entry entries[VMGEXIT_PSC_MAX_ENTRY ]; +} __packed; +#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12#define GHCB_MSR_TERM_REASON_SET_MASK 0xf
arch/x86/include/asm/sev.h +4 -0
@@ -128,6 +128,8 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddvoid __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages);void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op); +void snp_set_memory_shared (unsigned long vaddr,unsigned int npages); +void snp_set_memory_private (unsigned long vaddr,unsigned int npages);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -142,6 +144,8 @@ early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, unsignedstatic inline void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { }static inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { } +static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { } +static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }#endif #endif
arch/x86/include/uapi/asm/svm.h +2 -0
@@ -108,6 +108,7 @@#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 +#define SVM_VMGEXIT_PSC 0x80000010#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
@@ -219,6 +220,7 @@ { SVM_VMGEXIT_NMI_COMPLETE, "vmgexit_nmi_complete" }, \ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ + { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +168 -0
174 lines not on this page · raw message
arch/x86/mm/mem_encrypt_amd.c +13 -0
@@ -316,11 +316,24 @@ static void enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)static void amd_enc_status_change_prepare (unsigned long vaddr,int npages,bool enc) { +/* +* To maintain the security guarantees of SEV-SNP guests, make sure +* to invalidate the memory before encryption attribute is cleared. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && !enc) +snp_set_memory_shared (vaddr, npages); }/* Return true unconditionally: return value doesn't matter for the SEV side */ static bool amd_enc_status_change_finish (unsigned long vaddr,int npages,bool enc) { +/* +* After memory is mapped encrypted in the page table, validate it +* so that it is consistent with the page table updates. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && enc) +snp_set_memory_private (vaddr, npages); +if (!cc_platform_has (CC_ATTR_HOST_MEM_ENCRYPT ))enc_dec_hypercall (vaddr, npages, enc);
Signature · 1 line
2.25.1
[tip: x86/sev] x86/mm: Validate memory when changing the C-bit
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: dc3f3d2474b80eaee8be89f4c5eb344f10648f42 Gitweb: https://git.kernel.org/tip/dc3f3d2474b80eaee8be89f4c5eb344f10648f42 Author: Brijesh Singh <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:01 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 13:24:53 +02:00
x86/mm: Validate memory when changing the C-bit
Add the needed functionality to change pages state from shared to private and vice-versa using the Page State Change VMGEXIT as documented in the GHCB spec.
--- arch/x86/include/asm/sev-common.h | 22 ++++- arch/x86/include/asm/sev.h | 4 +- arch/x86/include/uapi/asm/svm.h | 2 +- arch/x86/kernel/sev.c | 168 +++++++++++++++++++++++++++++- arch/x86/mm/mem_encrypt_amd.c | 13 ++- 5 files changed, 209 insertions(+)
arch/x86/include/asm/sev-common.h +22 -0
@@ -105,6 +105,28 @@ enum psc_op {#define GHCB_HV_FT_SNP BIT_ULL(0) +/* SNP Page State Change NAE event */ +#define VMGEXIT_PSC_MAX_ENTRY 253 + +struct psc_hdr { +u16 cur_entry; +u16 end_entry; +u32 reserved; +} __packed; + +struct psc_entry { +u64 cur_page :12 , + gfn :40 , + operation :4 , + pagesize :1 , + reserved :7 ; +} __packed; + +struct snp_psc_desc { +struct psc_hdr hdr; +struct psc_entry entries[VMGEXIT_PSC_MAX_ENTRY ]; +} __packed; +#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12#define GHCB_MSR_TERM_REASON_SET_MASK 0xf
arch/x86/include/asm/sev.h +4 -0
@@ -128,6 +128,8 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddvoid __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages);void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op); +void snp_set_memory_shared (unsigned long vaddr,unsigned int npages); +void snp_set_memory_private (unsigned long vaddr,unsigned int npages);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -142,6 +144,8 @@ early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, unsignedstatic inline void __init early_snp_set_memory_shared (unsigned long vaddr,unsigned long paddr,unsigned int npages) { }static inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { } +static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { } +static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }#endif #endif
arch/x86/include/uapi/asm/svm.h +2 -0
@@ -108,6 +108,7 @@#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 +#define SVM_VMGEXIT_PSC 0x80000010#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
@@ -219,6 +220,7 @@ { SVM_VMGEXIT_NMI_COMPLETE, "vmgexit_nmi_complete" }, \ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ + { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +168 -0
174 lines not on this page · raw message
arch/x86/mm/mem_encrypt_amd.c +13 -0
@@ -316,11 +316,24 @@ static void enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)static void amd_enc_status_change_prepare (unsigned long vaddr,int npages,bool enc) { +/* +* To maintain the security guarantees of SEV-SNP guests, make sure +* to invalidate the memory before encryption attribute is cleared. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && !enc) +snp_set_memory_shared (vaddr, npages); }/* Return true unconditionally: return value doesn't matter for the SEV side */ static bool amd_enc_status_change_finish (unsigned long vaddr,int npages,bool enc) { +/* +* After memory is mapped encrypted in the page table, validate it +* so that it is consistent with the page table updates. +*/ +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && enc) +snp_set_memory_private (vaddr, npages); +if (!cc_platform_has (CC_ATTR_HOST_MEM_ENCRYPT ))enc_dec_hypercall (vaddr, npages, enc);
PATCH v12 22/46 x86/sev: Use SEV-SNP AP creation to start secondary CPUs
In reply to Brijesh SinghFrom: Tom Lendacky <[email protected]>
To provide a more secure way to start APs under SEV-SNP, use the SEV-SNP AP Creation NAE event. This allows for guest control over the AP register state rather than trusting the hypervisor with the SEV-ES Jump Table address.
During native_smp_prepare_cpus(), invoke an SEV-SNP function that, if SEV-SNP is active, will set/override apic->wakeup_secondary_cpu. This will allow the SEV-SNP AP Creation NAE event method to be used to boot the APs. As a result of installing the override when SEV-SNP is active, this method of starting the APs becomes the required method. The override function will fail to start the AP if the hypervisor does not have support for AP creation.
--- arch/x86/include/asm/sev-common.h | 1 + arch/x86/include/asm/sev.h | 4 + arch/x86/include/uapi/asm/svm.h | 5 + arch/x86/kernel/sev.c | 244 ++++++++++++++++++++++++++++++ arch/x86/kernel/smpboot.c | 3 + 5 files changed, 257 insertions(+)
arch/x86/include/asm/sev-common.h +1 -0
@@ -104,6 +104,7 @@ enum psc_op { (((u64)(v) & GENMASK_ULL(63, 12)) >> 12)#define GHCB_HV_FT_SNP BIT_ULL(0) +#define GHCB_HV_FT_SNP_AP_CREATION BIT_ULL(1)/* SNP Page State Change NAE event */ #define VMGEXIT_PSC_MAX_ENTRY 253
arch/x86/include/asm/sev.h +4 -0
@@ -66,6 +66,8 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);/* RMP page size */ #define RMP_PG_SIZE_4K 0 +#define RMPADJUST_VMSA_PAGE_BIT BIT(16) +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -130,6 +132,7 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddrvoid __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op);void snp_set_memory_shared (unsigned long vaddr,unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages); +void snp_set_wakeup_secondary_cpu (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -146,6 +149,7 @@ early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, unsigned istatic inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { }static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { } +static inline void snp_set_wakeup_secondary_cpu (void ) { }#endif #endif
arch/x86/include/uapi/asm/svm.h +5 -0
@@ -109,6 +109,10 @@#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1#define SVM_VMGEXIT_PSC 0x80000010 +#define SVM_VMGEXIT_AP_CREATION 0x80000013 +#define SVM_VMGEXIT_AP_CREATE_ON_INIT 0 +#define SVM_VMGEXIT_AP_CREATE 1 +#define SVM_VMGEXIT_AP_DESTROY 2#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
@@ -221,6 +225,7 @@ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ + { SVM_VMGEXIT_AP_CREATION, "vmgexit_ap_creation" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +244 -0
271 lines not on this page · raw message
arch/x86/kernel/smpboot.c +3 -0
@@ -82,6 +82,7 @@#include <asm/spec-ctrl.h> #include <asm/hw_irq.h> #include <asm/stackprotector.h> +#include <asm/sev.h> #ifdef CONFIG_ACPI_CPPC_LIB #include <acpi/cppc_acpi.h>
@@ -1436,6 +1437,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)smp_quirk_init_udelay ();speculative_store_bypass_ht_init (); + +snp_set_wakeup_secondary_cpu (); }void arch_thaw_secondary_cpus_begin (void )
Signature · 1 line
2.25.1
Sean Christopherson
maintainerRe: [PATCH v12 22/46] x86/sev: Use SEV-SNP AP creation to start secondary CPUs
Quoted 14 lines · Brijesh Singh
From: Tom Lendacky <[email protected]>
To provide a more secure way to start APs under SEV-SNP, use the SEV-SNP AP Creation NAE event. This allows for guest control over the AP register state rather than trusting the hypervisor with the SEV-ES Jump Table address.
During
native_smp_prepare_cpus(), invoke an SEV-SNP function that, if SEV-SNP is active, will set/overrideapic->wakeup_secondary_cpu. This will allow the SEV-SNP AP Creation NAE event method to be used to boot the APs. As a result of installing the override when SEV-SNP is active, this method of starting the APs becomes the required method. The override function will fail to start the AP if the hypervisor does not have support for AP creation.
...
Quoted 48 lines
arch/x86/kernel/sev.c +44
-0@@ -823,6 +843,230 @@ void snp_set_memory_private(unsigned long vaddr, unsigned int npages)pvalidate_pages (vaddr, npages, true); } +static int snp_set_vmsa (void *va,bool vmsa) +{ +u64 attrs; + +/* +* Running at VMPL0 allows the kernel to change the VMSA bit for a page +* using the RMPADJUST instruction. However, for the instruction to +* succeed it must target the permissions of a lesser privileged +* VMPL level, so use VMPL1 (refer to the RMPADJUST instruction in the +* AMD64 APM Volume 3). +*/ + attrs =1 ; +if (vmsa) + attrs |=RMPADJUST_VMSA_PAGE_BIT ; + +return rmpadjust ((unsigned long )va,RMP_PG_SIZE_4K , attrs); +} + +#define __ATTR_BASE (SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK) +#define INIT_CS_ATTRIBS (__ATTR_BASE | SVM_SELECTOR_READ_MASK | SVM_SELECTOR_CODE_MASK) +#define INIT_DS_ATTRIBS (__ATTR_BASE | SVM_SELECTOR_WRITE_MASK) + +#define INIT_LDTR_ATTRIBS (SVM_SELECTOR_P_MASK | 2) +#define INIT_TR_ATTRIBS (SVM_SELECTOR_P_MASK | 3) + +static void *snp_alloc_vmsa_page (void ) +{ +struct page *p; + +/* +* Allocate VMSA page to work around the SNP erratum where the CPU will +* incorrectly signal an RMP violation #PF if a large page (2MB or 1GB) +* collides with the RMP entry of VMSA page. The recommended workaround +* is to not use a large page. +*/ + +/* Allocate an 8k page which is also 8k-aligned */ + p =alloc_pages (GFP_KERNEL_ACCOUNT | __GFP_ZERO,1 ); +if (!p) +return NULL ; + +split_page (p,1 ); + +/* Free the first 4k. This page may be 2M/1G aligned and cannot be used. */
arch/x86/kernel/sev.c void snp_set_memory_private(unsigned long vaddr, unsigned int npages) · line 899
Quoted 10 lines
arch/x86/kernel/sev.c +10
-0+__free_page (p); + +return page_address (p +1 ); +} + +static void snp_cleanup_vmsa (struct sev_es_save_area *vmsa) +{ +int err; + + err =snp_set_vmsa (vmsa, false);
Uh, so what happens if a malicious guest does RMPADJUST to convert a VMSA page back to a "normal" page while the host is trying to VMRUN that VMSA? Does VMRUN fault?
Can Linux refuse to support this madness and instead require the ACPI MP wakeup protocol being proposed/implemented for TDX? That would allow KVM to have at least a chance of refusing to support AP "creation", which IMO is a CVE or three waiting to happen. From a KVM perspective, I don't ever want to be running a guest-defined VMSA.
Quoted 4 lines
arch/x86/kernel/sev.c +4
-0+if (err) +pr_err ("clear VMSA page failed (%u), leaking page\n" , err); +else +free_page ((unsigned long )vmsa);
Re: [PATCH v12 22/46] x86/sev: Use SEV-SNP AP creation to start secondary CPUs
Hi Sean,
Quoted 9 lines · Sean Christopherson
arch/x86/kernel/sev.c void snp_set_memory_private(unsigned long vaddr, unsigned int npages) · line 899
Quoted 5 lines
arch/x86/kernel/sev.c +5
-0+static void snp_cleanup_vmsa (struct sev_es_save_area *vmsa) +{ +int err; + + err =snp_set_vmsa (vmsa, false);Uh, so what happens if a malicious guest does RMPADJUST to convert a VMSA page back to a "normal" page while the host is trying to VMRUN that VMSA? Does VMRUN fault?
When SEV-SNP is enabled, the VMRUN instruction performs an additional security checks on various memory pages. In the case of VMSA page, hardware enforce that page is marked as "VMSA" in the RMP table. If not,
VMRUN will fail with VMEXIT_INVALID.
After the VMRUN is successful, the VMSA page is marked IN_USE by the hardware, any attempt to modify the RMP entries will result in FAIL_INUSE error. The IN_USE marking is automatically cleared by the hardware after the #VMEXIT.
Please see the APM vol2 section 15.36.12 for additional information.
Quoted 3 lines
Can Linux refuse to support this madness and instead require the ACPI MP wakeup protocol being proposed/implemented for TDX? That would allow KVM to have at
My two cents
In the current architecture, the HV track VMSAs by their SPA and guest controls when they are runnable. It provides flexibility to the guest, which can add and remove the VMSA. This flexibility may come in handy to support the kexec and reboot use cases. The current approach does not depend on ACPI; it will also come in handy to support microvm (minimalist machine type without PCI nor ACPI support).
Quoted 11 lines
least a chance of refusing to support AP "creation", which IMO is a CVE or three waiting to happen. From a KVM perspective, I don't ever want to be running a guest-defined VMSA.
Quoted 4 lines
arch/x86/kernel/sev.c +4
-0+if (err) +pr_err ("clear VMSA page failed (%u), leaking page\n" , err); +else +free_page ((unsigned long )vmsa);
Sean Christopherson
maintainerRe: [PATCH v12 22/46] x86/sev: Use SEV-SNP AP creation to start secondary CPUs
Quoted 19 lines · Brijesh Singh
Hi Sean,
Quoted 9 lines · Sean Christopherson
arch/x86/kernel/sev.c void snp_set_memory_private(unsigned long vaddr, unsigned int npages) · line 899
Quoted 5 lines
arch/x86/kernel/sev.c +5
-0+static void snp_cleanup_vmsa (struct sev_es_save_area *vmsa) +{ +int err; + + err =snp_set_vmsa (vmsa, false);Uh, so what happens if a malicious guest does RMPADJUST to convert a VMSA page back to a "normal" page while the host is trying to VMRUN that VMSA? Does VMRUN fault?
When SEV-SNP is enabled, the VMRUN instruction performs an additional security checks on various memory pages. In the case of VMSA page, hardware enforce that page is marked as "VMSA" in the RMP table. If not, VMRUN will fail with
VMEXIT_INVALID.
Quoted 6 lines
After the VMRUN is successful, the VMSA page is marked
IN_USEby the hardware, any attempt to modify the RMP entries will result inFAIL_INUSEerror. TheIN_USEmarking is automatically cleared by the hardware after the #VMEXIT.Please see the APM vol2 section 15.36.12 for additional information.
Thanks!
Quoted 9 lines
Quoted 2 lines
Can Linux refuse to support this madness and instead require the ACPI MP wakeup protocol being proposed/implemented for TDX? That would allow KVM to have at
My two cents
In the current architecture, the HV track VMSAs by their SPA and guest controls when they are runnable. It provides flexibility to the guest, which can add and remove the VMSA. This flexibility may come in handy to support the kexec and reboot use cases.
I understand it provides the guest flexibility, but IMO it completely inverts the separation of concerns between host and guest. The host should have control of when a vCPU is added/removed and with what state, and the guest should be able to verify/acknowledge any changes. This scheme gives the guest the bulk of the control, and doesn't even let the host verify much at all since the VMSA is opaque.
That the guest can yank the rug out from the host at any time just adds to the pain. VMEXIT_INVALID isn't the end of the world, but it breaks the assumption that such errors are host bugs. To guard against such behavior, the host would have to unmap the VMSA page in order to prevent unwanted RMPADJUST, and that gets ugly fast if a VMSA can be any arbitrary guest page.
Another example is the 2mb alignment erratum. Technically, the guest can't workaround the erratum with 100% certainty because there's no guarantee that the host uses the same alignment for gfns and pfns. I don't actually expect a host to use unaligned mappings, just pointing out how backwards this is.
I fully realize there's basically zero chance of getting any of this changed in hardware/firmware, but I'm hoping we can concoct a software/GHCB solution to the worst issues.
I don't see an way easy to address the guest getting to shove state directly into the VMSA, but the location of the VMSA gfn/pfn is a very solvable problem. E.g. the host gets full control over each vCPU's VMSA, and the host-provided VMSA is discoverable in the guest. That allows the guest to change vCPU state, e.g. for AP bringup, kexec, etc..., but gives the host the ability to protect itself without having to support arbitrary VMSA pages. E.g. the host can dynamically map/unmap the VMSA from the guest: map on fault, unmap on AP "creation", refuse to run the vCPU if its VMSA isn't in the unmap state. The VMSA pfn is fully host controlled, so there's no need for the guest to be aware of the 2mb alignment erratum.
Requiring such GHCB extensions in the guest would make Linux incompatible with hypervisors that aren't updated, but IMO that's not a ridiculous ask given that it would be in the best interested of any hypervisor that isn't running a fully trusted, paravirt VMPL0.
Quoted 3 lines
The current approach does not depend on
ACPI; it will also come in handy to support microvm (minimalist machine type without PCI nor ACPI support).
Eh, a microvm really shouldn't need AP bringup in the first place, just run all APs from time zero and route them to where they need to be.
[tip: x86/sev] x86/sev: Use SEV-SNP AP creation to start secondary CPUs
In reply to Brijesh SinghThe following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 0afb6b660a6b58cb336d1175ed687bf9525849a4 Gitweb: https://git.kernel.org/tip/0afb6b660a6b58cb336d1175ed687bf9525849a4 Author: Tom Lendacky <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:32 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:06:49 +02:00
x86/sev: Use SEV-SNP AP creation to start secondary CPUs
To provide a more secure way to start APs under SEV-SNP, use the SEV-SNP AP Creation NAE event. This allows for guest control over the AP register state rather than trusting the hypervisor with the SEV-ES Jump Table address.
During native_smp_prepare_cpus(), invoke an SEV-SNP function that, if SEV-SNP is active, will set/override apic->wakeup_secondary_cpu. This will allow the SEV-SNP AP Creation NAE event method to be used to boot the APs. As a result of installing the override when SEV-SNP is active, this method of starting the APs becomes the required method. The override function will fail to start the AP if the hypervisor does not have support for AP creation.
[ bp: Work in forgotten review comments. ]
--- arch/x86/include/asm/sev-common.h | 1 +- arch/x86/include/asm/sev.h | 4 +- arch/x86/include/uapi/asm/svm.h | 5 +- arch/x86/kernel/sev.c | 242 +++++++++++++++++++++++++++++- arch/x86/kernel/smpboot.c | 3 +- 5 files changed, 255 insertions(+)
arch/x86/include/asm/sev-common.h +1 -0
@@ -104,6 +104,7 @@ enum psc_op { (((u64)(v) & GENMASK_ULL(63, 12)) >> 12)#define GHCB_HV_FT_SNP BIT_ULL(0) +#define GHCB_HV_FT_SNP_AP_CREATION BIT_ULL(1)/* SNP Page State Change NAE event */ #define VMGEXIT_PSC_MAX_ENTRY 253
arch/x86/include/asm/sev.h +4 -0
@@ -66,6 +66,8 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);/* RMP page size */ #define RMP_PG_SIZE_4K 0 +#define RMPADJUST_VMSA_PAGE_BIT BIT(16) +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -130,6 +132,7 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddrvoid __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op);void snp_set_memory_shared (unsigned long vaddr,unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages); +void snp_set_wakeup_secondary_cpu (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -146,6 +149,7 @@ early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, unsigned istatic inline void __init snp_prep_memory (unsigned long paddr,unsigned int sz,enum psc_op op) { }static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { } +static inline void snp_set_wakeup_secondary_cpu (void ) { }#endif #endif
arch/x86/include/uapi/asm/svm.h +5 -0
@@ -109,6 +109,10 @@#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1#define SVM_VMGEXIT_PSC 0x80000010 +#define SVM_VMGEXIT_AP_CREATION 0x80000013 +#define SVM_VMGEXIT_AP_CREATE_ON_INIT 0 +#define SVM_VMGEXIT_AP_CREATE 1 +#define SVM_VMGEXIT_AP_DESTROY 2#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
@@ -221,6 +225,7 @@ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ + { SVM_VMGEXIT_AP_CREATION, "vmgexit_ap_creation" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +242 -0
269 lines not on this page · raw message
arch/x86/kernel/smpboot.c +3 -0
@@ -82,6 +82,7 @@#include <asm/spec-ctrl.h> #include <asm/hw_irq.h> #include <asm/stackprotector.h> +#include <asm/sev.h> /* representing HT siblings of each logical CPU */ DEFINE_PER_CPU_READ_MOSTLY (cpumask_var_t, cpu_sibling_map);
@@ -1430,6 +1431,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)smp_quirk_init_udelay ();speculative_store_bypass_ht_init (); + +snp_set_wakeup_secondary_cpu (); }void arch_thaw_secondary_cpus_begin (void )
PATCH v12 23/46 x86/head/64: Re-enable stack protection
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Due to commit 103a4908ad4d ("x86/head/64: Disable stack protection for head$(BITS).o"), kernel/head{32,64}.c are compiled with -fno-stack-protector to allow a call to set_bringup_idt_handler(), which would otherwise have stack protection enabled with CONFIG_STACKPROTECTOR_STRONG.
While sufficient for that case, there may still be issues with calls to any external functions that were compiled with stack protection enabled that in-turn make stack-protected calls, or if the exception handlers set up by set_bringup_idt_handler() make calls to stack-protected functions.
Subsequent patches for SEV-SNP CPUID validation support will introduce both such cases. Attempting to disable stack protection for everything in scope to address that is prohibitive since much of the code, like SEV-ES #VC handler, is shared code that remains in use after boot and could benefit from having stack protection enabled. Attempting to inline calls is brittle and can quickly balloon out to library/helper code where that's not really an option.
Instead, re-enable stack protection for head32.c/head64.c, and make the appropriate changes to ensure the segment used for the stack canary is initialized in advance of any stack-protected C calls.
For head64.c:
- The BSP will enter from startup_64() and call into C code (startup_64_setup_env()) shortly after setting up the stack, which may result in calls to stack-protected code. Set up %gs early to allow for this safely.
- APs will enter from secondary_startup_64*(), and %gs will be set up soon after. There is one call to C code prior to %gs being setup (__startup_secondary_64()), but it is only to fetch 'sme_me_mask' global, so just load 'sme_me_mask' directly instead, and remove the now-unused __startup_secondary_64() function.
For head32.c:
- BSPs/APs will set %fs to __BOOT_DS prior to any C calls. In recent kernels, the compiler is configured to access the stack canary at %fs:__stack_chk_guard [1], which overlaps with the initial per-cpu '__stack_chk_guard' variable in the initial/"master" .data..percpu area. This is sufficient to allow access to the canary for use during initial startup, so no changes are needed there.
[1] commit 3fb0fdb3bbe7 ("x86/stackprotector/32: Make the canary into a regular percpu variable")
--- arch/x86/include/asm/setup.h | 1 - arch/x86/kernel/Makefile | 2 -- arch/x86/kernel/head64.c | 9 --------- arch/x86/kernel/head_64.S | 24 +++++++++++++++++++++--- 4 files changed, 21 insertions(+), 15 deletions(-)
arch/x86/include/asm/setup.h +0 -1
@@ -49,7 +49,6 @@ extern unsigned long saved_video_mode;extern void reserve_standard_io_resources (void );extern void i386_reserve_resources (void );extern unsigned long __startup_64 (unsigned long physaddr,struct boot_params *bp); -extern unsigned long __startup_secondary_64 (void );extern void startup_64_setup_env (unsigned long physbase);extern void early_setup_idt (void );extern void __init do_early_exception (struct pt_regs *regs,int trapnr);
arch/x86/kernel/Makefile +0 -2
@@ -46,8 +46,6 @@ endif # non-deterministic coverage. KCOV_INSTRUMENT := n -CFLAGS_head$(BITS).o += -fno-stack-protector - CFLAGS_irq.o := -I $(srctree)/$(src)/../include/asm/trace obj-y := process_$(BITS).o signal.o
arch/x86/kernel/head64.c +0 -9
@@ -318,15 +318,6 @@ unsigned long __head __startup_64(unsigned long physaddr,return sme_postprocess_startup (bp, pmd); } -unsigned long __startup_secondary_64 (void ) -{ -/* -* Return the SME encryption mask (if SME is active) to be used as a -* modifier for the initial pgdir entry programmed into CR3. -*/ -return sme_get_me_mask (); -} -/* Wipe all early page tables except for the kernel symbol map */ static void __init reset_early_page_tables (void ) {
arch/x86/kernel/head_64.S +21 -3
@@ -65,6 +65,22 @@ SYM_CODE_START_NOALIGN(startup_64) leaq (__end_init_task - FRAME_SIZE)(%rip), %rsp leaq _text(%rip), %rdi + + /* + * initial_gs points to initial fixed_percpu_data struct with storage for + * the stack protector canary. Global pointer fixups are needed at this + * stage, so apply them as is done in fixup_pointer(), and initialize %gs + * such that the canary can be accessed at %gs:40 for subsequent C calls. + */ + movl $MSR_GS_BASE, %ecx + movq initial_gs(%rip), %rax + movq $_text, %rdx + subq %rdx, %rax + addq %rdi, %rax + movq %rax, %rdx + shrq $32, %rdx + wrmsr + pushq %rsi call startup_64_setup_env popq %rsi
@@ -145,9 +161,11 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) * Retrieve the modifier (SME encryption mask if SME is active) to be * added to the initial pgdir entry that will be programmed into CR3. */ - pushq %rsi - call __startup_secondary_64 - popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + movq sme_me_mask, %rax +#else + xorq %rax, %rax +#endif /* Form the CR3 value being sure to include the CR3 modifier */ addq $(init_top_pgt - __START_KERNEL_map), %rax
Signature · 1 line
2.25.1
[tip: x86/sev] x86/head/64: Re-enable stack protection
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 469693d8f62299709e8ba56d8fb3da9ea990213c Gitweb: https://git.kernel.org/tip/469693d8f62299709e8ba56d8fb3da9ea990213c Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:17 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:06:55 +02:00
x86/head/64: Re-enable stack protection
Due to
103a4908ad4d ("x86/head/64: Disable stack protection for head$(BITS).o")kernel/head{32,64}.c are compiled with -fno-stack-protector to allow a call to set_bringup_idt_handler(), which would otherwise have stack protection enabled with CONFIG_STACKPROTECTOR_STRONG.
While sufficient for that case, there may still be issues with calls to any external functions that were compiled with stack protection enabled that in-turn make stack-protected calls, or if the exception handlers set up by set_bringup_idt_handler() make calls to stack-protected functions.
Subsequent patches for SEV-SNP CPUID validation support will introduce both such cases. Attempting to disable stack protection for everything in scope to address that is prohibitive since much of the code, like the SEV-ES #VC handler, is shared code that remains in use after boot and could benefit from having stack protection enabled. Attempting to inline calls is brittle and can quickly balloon out to library/helper code where that's not really an option.
Instead, re-enable stack protection for head32.c/head64.c, and make the appropriate changes to ensure the segment used for the stack canary is initialized in advance of any stack-protected C calls.
For head64.c:
- The BSP will enter from startup_64() and call into C code (startup_64_setup_env()) shortly after setting up the stack, which may result in calls to stack-protected code. Set up %gs early to allow for this safely.
- APs will enter from secondary_startup_64*(), and %gs will be set up soon after. There is one call to C code prior to %gs being setup (__startup_secondary_64()), but it is only to fetch 'sme_me_mask' global, so just load 'sme_me_mask' directly instead, and remove the now-unused __startup_secondary_64() function.
For head32.c:
- BSPs/APs will set %fs to __BOOT_DS prior to any C calls. In recent kernels, the compiler is configured to access the stack canary at %fs:__stack_chk_guard [1], which overlaps with the initial per-cpu '__stack_chk_guard' variable in the initial/"master" .data..percpu area. This is sufficient to allow access to the canary for use during initial startup, so no changes are needed there.
[1] 3fb0fdb3bbe7 ("x86/stackprotector/32: Make the canary into a regular percpu variable")
[ bp: Massage commit message. ]
--- arch/x86/include/asm/setup.h | 1 - arch/x86/kernel/Makefile | 2 -- arch/x86/kernel/head64.c | 9 --------- arch/x86/kernel/head_64.S | 24 +++++++++++++++++++++--- 4 files changed, 21 insertions(+), 15 deletions(-)
arch/x86/include/asm/setup.h +0 -1
@@ -50,7 +50,6 @@ extern unsigned long saved_video_mode;extern void reserve_standard_io_resources (void );extern void i386_reserve_resources (void );extern unsigned long __startup_64 (unsigned long physaddr,struct boot_params *bp); -extern unsigned long __startup_secondary_64 (void );extern void startup_64_setup_env (unsigned long physbase);extern void early_setup_idt (void );extern void __init do_early_exception (struct pt_regs *regs,int trapnr);
arch/x86/kernel/Makefile +0 -2
@@ -46,8 +46,6 @@ endif # non-deterministic coverage. KCOV_INSTRUMENT := n -CFLAGS_head$(BITS).o += -fno-stack-protector - CFLAGS_irq.o := -I $(srctree)/$(src)/../include/asm/trace obj-y := process_$(BITS).o signal.o
arch/x86/kernel/head64.c +0 -9
@@ -318,15 +318,6 @@ unsigned long __head __startup_64(unsigned long physaddr,return sme_postprocess_startup (bp, pmd); } -unsigned long __startup_secondary_64 (void ) -{ -/* -* Return the SME encryption mask (if SME is active) to be used as a -* modifier for the initial pgdir entry programmed into CR3. -*/ -return sme_get_me_mask (); -} -/* Wipe all early page tables except for the kernel symbol map */ static void __init reset_early_page_tables (void ) {
arch/x86/kernel/head_64.S +21 -3
@@ -65,6 +65,22 @@ SYM_CODE_START_NOALIGN(startup_64) leaq (__end_init_task - FRAME_SIZE)(%rip), %rsp leaq _text(%rip), %rdi + + /* + * initial_gs points to initial fixed_percpu_data struct with storage for + * the stack protector canary. Global pointer fixups are needed at this + * stage, so apply them as is done in fixup_pointer(), and initialize %gs + * such that the canary can be accessed at %gs:40 for subsequent C calls. + */ + movl $MSR_GS_BASE, %ecx + movq initial_gs(%rip), %rax + movq $_text, %rdx + subq %rdx, %rax + addq %rdi, %rax + movq %rax, %rdx + shrq $32, %rdx + wrmsr + pushq %rsi call startup_64_setup_env popq %rsi
@@ -147,9 +163,11 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) * Retrieve the modifier (SME encryption mask if SME is active) to be * added to the initial pgdir entry that will be programmed into CR3. */ - pushq %rsi - call __startup_secondary_64 - popq %rsi +#ifdef CONFIG_AMD_MEM_ENCRYPT + movq sme_me_mask, %rax +#else + xorq %rax, %rax +#endif /* Form the CR3 value being sure to include the CR3 modifier */ addq $(init_top_pgt - __START_KERNEL_map), %rax
PATCH v12 24/46 x86/compressed/acpi: Move EFI detection to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
--- arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/acpi.c | 28 +++++++---------- arch/x86/boot/compressed/efi.c | 50 +++++++++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 16 ++++++++++ 4 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 arch/x86/boot/compressed/efi.c
arch/x86/boot/compressed/Makefile +1 -0
@@ -103,6 +103,7 @@ endif vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o +vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a $(obj)/vmlinux: $(vmlinux-objs-y) $(efi-obj-y) FORCE
arch/x86/boot/compressed/acpi.c +10 -18
@@ -87,7 +87,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void)efi_system_table_64_t *systab;struct efi_setup_data *esd;struct efi_info *ei; -char *sig; +enum efi_type et; esd = (struct efi_setup_data *)get_kexec_setup_data_addr ();if (!esd)
@@ -98,10 +98,9 @@ static acpi_physical_address kexec_get_rsdp_addr(void)return 0 ; } - ei = &boot_params->efi_info; - sig = (char *)&ei->efi_loader_signature; -if (strncmp (sig,EFI64_LOADER_SIGNATURE ,4 )) { -debug_putstr ("Wrong kexec EFI loader signature.\n" ); + et =efi_get_type (boot_params); +if (et !=EFI_TYPE_64 ) { +debug_putstr ("Unexpected kexec EFI environment (expected 64-bit EFI).\n" );return 0 ; }
@@ -122,29 +121,22 @@ static acpi_physical_address efi_get_rsdp_addr(void)unsigned long systab, config_tables;unsigned int nr_tables;struct efi_info *ei; +enum efi_type et;bool efi_64; -char *sig; - - ei = &boot_params->efi_info; - sig = (char *)&ei->efi_loader_signature; -if (!strncmp (sig,EFI64_LOADER_SIGNATURE ,4 )) { + et =efi_get_type (boot_params); +if (et ==EFI_TYPE_64 ) efi_64 = true; - }else if (!strncmp (sig,EFI32_LOADER_SIGNATURE ,4 )) { +else if (et ==EFI_TYPE_32 ) efi_64 = false; - }else { -debug_putstr ("Wrong EFI loader signature.\n" ); +else return 0 ; - }/* Get systab from boot params. */ + ei = &boot_params->efi_info;#ifdef CONFIG_X86_64 systab = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 );#else -if (ei->efi_systab_hi || ei->efi_memmap_hi) { -debug_putstr ("Error getting RSDP address: EFI system table located above 4GB.\n" ); -return 0 ; - } systab = ei->efi_systab;#endif if (!systab)
arch/x86/boot/compressed/efi.c new file +50 -0
50 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +16 -0
@@ -176,4 +176,20 @@ void boot_stage2_vc(void);unsigned long sev_verify_cbit (unsigned long cr3); +enum efi_type { +EFI_TYPE_64 , +EFI_TYPE_32 , +EFI_TYPE_NONE , +}; + +#ifdef CONFIG_EFI +/* helpers for early EFI config table access */ +enum efi_type efi_get_type (struct boot_params *bp); +#else +static inline enum efi_type efi_get_type (struct boot_params *bp) +{ +return EFI_TYPE_NONE ; +} +#endif /* CONFIG_EFI */ +#endif /* BOOT_COMPRESSED_MISC_H */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/acpi: Move EFI detection to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 7c4146e8885512719a50b641e9277a1712e052ff Gitweb: https://git.kernel.org/tip/7c4146e8885512719a50b641e9277a1712e052ff Author: Michael Roth <[email protected]> AuthorDate: Wed, 09 Feb 2022 12:10:18 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:07:02 +02:00
x86/compressed/acpi: Move EFI detection to helper
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
First, carve out the functionality which determines the EFI environment type the machine is booting on.
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/Makefile | 1 +- arch/x86/boot/compressed/acpi.c | 28 ++++++----------- arch/x86/boot/compressed/efi.c | 50 ++++++++++++++++++++++++++++++- arch/x86/boot/compressed/misc.h | 16 ++++++++++- 4 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 arch/x86/boot/compressed/efi.c
arch/x86/boot/compressed/Makefile +1 -0
@@ -103,6 +103,7 @@ endif vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o +vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a $(obj)/vmlinux: $(vmlinux-objs-y) $(efi-obj-y) FORCE
arch/x86/boot/compressed/acpi.c +10 -18
@@ -87,7 +87,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void)efi_system_table_64_t *systab;struct efi_setup_data *esd;struct efi_info *ei; -char *sig; +enum efi_type et; esd = (struct efi_setup_data *)get_kexec_setup_data_addr ();if (!esd)
@@ -98,10 +98,9 @@ static acpi_physical_address kexec_get_rsdp_addr(void)return 0 ; } - ei = &boot_params->efi_info; - sig = (char *)&ei->efi_loader_signature; -if (strncmp (sig,EFI64_LOADER_SIGNATURE ,4 )) { -debug_putstr ("Wrong kexec EFI loader signature.\n" ); + et =efi_get_type (boot_params); +if (et !=EFI_TYPE_64 ) { +debug_putstr ("Unexpected kexec EFI environment (expected 64-bit EFI).\n" );return 0 ; }
@@ -122,29 +121,22 @@ static acpi_physical_address efi_get_rsdp_addr(void)unsigned long systab, config_tables;unsigned int nr_tables;struct efi_info *ei; +enum efi_type et;bool efi_64; -char *sig; - - ei = &boot_params->efi_info; - sig = (char *)&ei->efi_loader_signature; -if (!strncmp (sig,EFI64_LOADER_SIGNATURE ,4 )) { + et =efi_get_type (boot_params); +if (et ==EFI_TYPE_64 ) efi_64 = true; - }else if (!strncmp (sig,EFI32_LOADER_SIGNATURE ,4 )) { +else if (et ==EFI_TYPE_32 ) efi_64 = false; - }else { -debug_putstr ("Wrong EFI loader signature.\n" ); +else return 0 ; - }/* Get systab from boot params. */ + ei = &boot_params->efi_info;#ifdef CONFIG_X86_64 systab = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 );#else -if (ei->efi_systab_hi || ei->efi_memmap_hi) { -debug_putstr ("Error getting RSDP address: EFI system table located above 4GB.\n" ); -return 0 ; - } systab = ei->efi_systab;#endif if (!systab)
arch/x86/boot/compressed/efi.c new file +50 -0
50 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +16 -0
@@ -176,4 +176,20 @@ void boot_stage2_vc(void);unsigned long sev_verify_cbit (unsigned long cr3); +enum efi_type { +EFI_TYPE_64 , +EFI_TYPE_32 , +EFI_TYPE_NONE , +}; + +#ifdef CONFIG_EFI +/* helpers for early EFI config table access */ +enum efi_type efi_get_type (struct boot_params *bp); +#else +static inline enum efi_type efi_get_type (struct boot_params *bp) +{ +return EFI_TYPE_NONE ; +} +#endif /* CONFIG_EFI */ +#endif /* BOOT_COMPRESSED_MISC_H */
PATCH v12 25/46 x86/compressed/acpi: Move EFI system table lookup to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
--- arch/x86/boot/compressed/acpi.c | 21 +++++++-------------- arch/x86/boot/compressed/efi.c | 29 +++++++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 6 ++++++ 3 files changed, 42 insertions(+), 14 deletions(-)
arch/x86/boot/compressed/acpi.c +7 -14
@@ -105,7 +105,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void) }/* Get systab from boot params. */ - systab = (efi_system_table_64_t *) (ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 )); + systab = (efi_system_table_64_t *)efi_get_system_table (boot_params);if (!systab)error ("EFI system table not found in kexec boot_params." );
@@ -118,9 +118,8 @@ static acpi_physical_address kexec_get_rsdp_addr(void) { return 0; }static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI -unsigned long systab, config_tables; +unsigned long systab_pa, config_tables;unsigned int nr_tables; -struct efi_info *ei;enum efi_type et;bool efi_64;
@@ -132,24 +131,18 @@ static acpi_physical_address efi_get_rsdp_addr(void)else return 0 ; -/* Get systab from boot params. */ - ei = &boot_params->efi_info; -#ifdef CONFIG_X86_64 - systab = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 ); -#else - systab = ei->efi_systab; -#endif -if (!systab) -error ("EFI system table not found." ); + systab_pa =efi_get_system_table (boot_params); +if (!systab_pa) +error ("EFI support advertised, but unable to locate system table." );/* Handle EFI bitness properly */ if (efi_64) { -efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab; +efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab_pa; config_tables = stbl->tables; nr_tables = stbl->nr_tables; }else { -efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab; +efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab_pa; config_tables = stbl->tables; nr_tables = stbl->nr_tables;
arch/x86/boot/compressed/efi.c +29 -0
@@ -48,3 +48,32 @@ enum efi_type efi_get_type(struct boot_params *bp)return et; } + +/** +* efi_get_system_table - Given a pointer to boot_params, retrieve the physical address +* of the EFI system table. +* +* @bp: pointer to boot_params +* +* Return: EFI system table address on success. On error, return 0. +*/ +unsigned long efi_get_system_table (struct boot_params *bp) +{ +unsigned long sys_tbl_pa; +struct efi_info *ei; +enum efi_type et; + +/* Get systab from boot params. */ + ei = &bp->efi_info; +#ifdef CONFIG_X86_64 + sys_tbl_pa = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 ); +#else + sys_tbl_pa = ei->efi_systab; +#endif +if (!sys_tbl_pa) { +debug_putstr ("EFI system table not found." ); +return 0 ; + } + +return sys_tbl_pa; +}
arch/x86/boot/compressed/misc.h +6 -0
@@ -185,11 +185,17 @@ enum efi_type {#ifdef CONFIG_EFI /* helpers for early EFI config table access */ enum efi_type efi_get_type (struct boot_params *bp); +unsigned long efi_get_system_table (struct boot_params *bp);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {return EFI_TYPE_NONE ; } + +static inline unsigned long efi_get_system_table (struct boot_params *bp) +{ +return 0 ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/acpi: Move EFI system table lookup to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 58f3e6b71f42f99ab5d0ab26ddf6e7ee5631f5db Gitweb: https://git.kernel.org/tip/58f3e6b71f42f99ab5d0ab26ddf6e7ee5631f5db Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:05 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:07:09 +02:00
x86/compressed/acpi: Move EFI system table lookup to helper
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
--- arch/x86/boot/compressed/acpi.c | 21 +++++++-------------- arch/x86/boot/compressed/efi.c | 29 +++++++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 6 ++++++ 3 files changed, 42 insertions(+), 14 deletions(-)
arch/x86/boot/compressed/acpi.c +7 -14
@@ -105,7 +105,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void) }/* Get systab from boot params. */ - systab = (efi_system_table_64_t *) (ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 )); + systab = (efi_system_table_64_t *)efi_get_system_table (boot_params);if (!systab)error ("EFI system table not found in kexec boot_params." );
@@ -118,9 +118,8 @@ static acpi_physical_address kexec_get_rsdp_addr(void) { return 0; }static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI -unsigned long systab, config_tables; +unsigned long systab_pa, config_tables;unsigned int nr_tables; -struct efi_info *ei;enum efi_type et;bool efi_64;
@@ -132,24 +131,18 @@ static acpi_physical_address efi_get_rsdp_addr(void)else return 0 ; -/* Get systab from boot params. */ - ei = &boot_params->efi_info; -#ifdef CONFIG_X86_64 - systab = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 ); -#else - systab = ei->efi_systab; -#endif -if (!systab) -error ("EFI system table not found." ); + systab_pa =efi_get_system_table (boot_params); +if (!systab_pa) +error ("EFI support advertised, but unable to locate system table." );/* Handle EFI bitness properly */ if (efi_64) { -efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab; +efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab_pa; config_tables = stbl->tables; nr_tables = stbl->nr_tables; }else { -efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab; +efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab_pa; config_tables = stbl->tables; nr_tables = stbl->nr_tables;
arch/x86/boot/compressed/efi.c +29 -0
@@ -48,3 +48,32 @@ enum efi_type efi_get_type(struct boot_params *bp)return et; } + +/** +* efi_get_system_table - Given a pointer to boot_params, retrieve the physical address +* of the EFI system table. +* +* @bp: pointer to boot_params +* +* Return: EFI system table address on success. On error, return 0. +*/ +unsigned long efi_get_system_table (struct boot_params *bp) +{ +unsigned long sys_tbl_pa; +struct efi_info *ei; +enum efi_type et; + +/* Get systab from boot params. */ + ei = &bp->efi_info; +#ifdef CONFIG_X86_64 + sys_tbl_pa = ei->efi_systab | ((__u64 )ei->efi_systab_hi <<32 ); +#else + sys_tbl_pa = ei->efi_systab; +#endif +if (!sys_tbl_pa) { +debug_putstr ("EFI system table not found." ); +return 0 ; + } + +return sys_tbl_pa; +}
arch/x86/boot/compressed/misc.h +6 -0
@@ -185,11 +185,17 @@ enum efi_type {#ifdef CONFIG_EFI /* helpers for early EFI config table access */ enum efi_type efi_get_type (struct boot_params *bp); +unsigned long efi_get_system_table (struct boot_params *bp);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {return EFI_TYPE_NONE ; } + +static inline unsigned long efi_get_system_table (struct boot_params *bp) +{ +return 0 ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
PATCH v12 26/46 x86/compressed/acpi: Move EFI config table lookup to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
--- arch/x86/boot/compressed/acpi.c | 25 ++++++------------- arch/x86/boot/compressed/efi.c | 43 +++++++++++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 9 +++++++ 3 files changed, 60 insertions(+), 17 deletions(-)
arch/x86/boot/compressed/acpi.c +8 -17
@@ -118,10 +118,13 @@ static acpi_physical_address kexec_get_rsdp_addr(void) { return 0; }static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI -unsigned long systab_pa, config_tables; +unsigned long cfg_tbl_pa =0 ; +unsigned int cfg_tbl_len; +unsigned long systab_pa;unsigned int nr_tables;enum efi_type et;bool efi_64; +int ret; et =efi_get_type (boot_params);if (et ==EFI_TYPE_64 )
@@ -135,23 +138,11 @@ static acpi_physical_address efi_get_rsdp_addr(void)if (!systab_pa)error ("EFI support advertised, but unable to locate system table." ); -/* Handle EFI bitness properly */ -if (efi_64) { -efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab_pa; - - config_tables = stbl->tables; - nr_tables = stbl->nr_tables; - }else { -efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab_pa; - - config_tables = stbl->tables; - nr_tables = stbl->nr_tables; - } - -if (!config_tables) -error ("EFI config tables not found." ); + ret =efi_get_conf_table (boot_params, &cfg_tbl_pa, &cfg_tbl_len); +if (ret || !cfg_tbl_pa) +error ("EFI config table not found." ); -return __efi_get_rsdp_addr (config_tables, nr_tables, efi_64); +return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len, efi_64);#else return 0 ;#endif
arch/x86/boot/compressed/efi.c +43 -0
46 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +9 -0
@@ -186,6 +186,8 @@ enum efi_type {/* helpers for early EFI config table access */ enum efi_type efi_get_type (struct boot_params *bp);unsigned long efi_get_system_table (struct boot_params *bp); +int efi_get_conf_table (struct boot_params *bp,unsigned long *cfg_tbl_pa, +unsigned int *cfg_tbl_len);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {
@@ -196,6 +198,13 @@ static inline unsigned long efi_get_system_table(struct boot_params *bp) {return 0 ; } + +static inline int efi_get_conf_table (struct boot_params *bp, +unsigned long *cfg_tbl_pa, +unsigned int *cfg_tbl_len) +{ +return -ENOENT ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/acpi: Move EFI config table lookup to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 61c14ceda8405f37545a0983d6b9bc45c6236793 Gitweb: https://git.kernel.org/tip/61c14ceda8405f37545a0983d6b9bc45c6236793 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:06 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:07:15 +02:00
x86/compressed/acpi: Move EFI config table lookup to helper
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
[ bp: Remove superfluous zeroing of a stack variable. ]
--- arch/x86/boot/compressed/acpi.c | 25 ++++++------------- arch/x86/boot/compressed/efi.c | 43 ++++++++++++++++++++++++++++++++- arch/x86/boot/compressed/misc.h | 9 +++++++- 3 files changed, 60 insertions(+), 17 deletions(-)
arch/x86/boot/compressed/acpi.c +8 -17
@@ -118,10 +118,13 @@ static acpi_physical_address kexec_get_rsdp_addr(void) { return 0; }static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI -unsigned long systab_pa, config_tables; +unsigned long cfg_tbl_pa =0 ; +unsigned int cfg_tbl_len; +unsigned long systab_pa;unsigned int nr_tables;enum efi_type et;bool efi_64; +int ret; et =efi_get_type (boot_params);if (et ==EFI_TYPE_64 )
@@ -135,23 +138,11 @@ static acpi_physical_address efi_get_rsdp_addr(void)if (!systab_pa)error ("EFI support advertised, but unable to locate system table." ); -/* Handle EFI bitness properly */ -if (efi_64) { -efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab_pa; - - config_tables = stbl->tables; - nr_tables = stbl->nr_tables; - }else { -efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab_pa; - - config_tables = stbl->tables; - nr_tables = stbl->nr_tables; - } - -if (!config_tables) -error ("EFI config tables not found." ); + ret =efi_get_conf_table (boot_params, &cfg_tbl_pa, &cfg_tbl_len); +if (ret || !cfg_tbl_pa) +error ("EFI config table not found." ); -return __efi_get_rsdp_addr (config_tables, nr_tables, efi_64); +return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len, efi_64);#else return 0 ;#endif
arch/x86/boot/compressed/efi.c +43 -0
46 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +9 -0
@@ -186,6 +186,8 @@ enum efi_type {/* helpers for early EFI config table access */ enum efi_type efi_get_type (struct boot_params *bp);unsigned long efi_get_system_table (struct boot_params *bp); +int efi_get_conf_table (struct boot_params *bp,unsigned long *cfg_tbl_pa, +unsigned int *cfg_tbl_len);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {
@@ -196,6 +198,13 @@ static inline unsigned long efi_get_system_table(struct boot_params *bp) {return 0 ; } + +static inline int efi_get_conf_table (struct boot_params *bp, +unsigned long *cfg_tbl_pa, +unsigned int *cfg_tbl_len) +{ +return -ENOENT ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
PATCH v12 27/46 x86/compressed/acpi: Move EFI vendor table lookup to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
--- arch/x86/boot/compressed/acpi.c | 68 +++++++++++-------------------- arch/x86/boot/compressed/efi.c | 72 +++++++++++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 13 ++++++ 3 files changed, 108 insertions(+), 45 deletions(-)
arch/x86/boot/compressed/acpi.c +23 -45
@@ -20,48 +20,31 @@*/ struct mem_vector immovable_mem[MAX_NUMNODES *2 ]; -/* -* Search EFI system tables for RSDP. If both ACPI_20_TABLE_GUID and -* ACPI_TABLE_GUID are found, take the former, which has more features. -*/ static acpi_physical_address -__efi_get_rsdp_addr (unsigned long config_tables,unsigned int nr_tables, -bool efi_64) +__efi_get_rsdp_addr (unsigned long cfg_tbl_pa,unsigned int cfg_tbl_len) { -acpi_physical_address rsdp_addr =0 ; -#ifdef CONFIG_EFI -int i; - -/* Get EFI tables from systab. */ -for (i =0 ; i < nr_tables; i++) { -acpi_physical_address table; -efi_guid_t guid; - -if (efi_64) { -efi_config_table_64_t *tbl = (efi_config_table_64_t *)config_tables + i; - - guid = tbl->guid; - table = tbl->table; - -if (!IS_ENABLED (CONFIG_X86_64 ) && table >>32 ) { -debug_putstr ("Error getting RSDP address: EFI config table located above 4GB.\n" ); -return 0 ; - } - }else { -efi_config_table_32_t *tbl = (efi_config_table_32_t *)config_tables + i; - - guid = tbl->guid; - table = tbl->table; - } +unsigned long rsdp_addr; +int ret; -if (!(efi_guidcmp (guid,ACPI_TABLE_GUID ))) - rsdp_addr = table; -else if (!(efi_guidcmp (guid,ACPI_20_TABLE_GUID ))) -return table; - } +/* +* Search EFI system tables for RSDP. Preferred is ACPI_20_TABLE_GUID to +* ACPI_TABLE_GUID because it has more features. +*/ + rsdp_addr =efi_find_vendor_table (boot_params, cfg_tbl_pa, cfg_tbl_len, +ACPI_20_TABLE_GUID ); +if (rsdp_addr) +return (acpi_physical_address )rsdp_addr; + +/* No ACPI_20_TABLE_GUID found, fallback to ACPI_TABLE_GUID. */ + rsdp_addr =efi_find_vendor_table (boot_params, cfg_tbl_pa, cfg_tbl_len, +ACPI_TABLE_GUID ); +if (rsdp_addr) +return (acpi_physical_address )rsdp_addr; + +debug_putstr ("Error getting RSDP address.\n" );#endif -return rsdp_addr; +return 0 ; }/* EFI/kexec support is 64-bit only. */
@@ -109,7 +92,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void)if (!systab)error ("EFI system table not found in kexec boot_params." ); - return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables, true); + return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables); }#else static acpi_physical_address kexec_get_rsdp_addr (void ) {return 0 ; }
@@ -123,15 +106,10 @@ static acpi_physical_address efi_get_rsdp_addr(void)unsigned long systab_pa;unsigned int nr_tables;enum efi_type et; -bool efi_64;int ret; et =efi_get_type (boot_params); -if (et ==EFI_TYPE_64 ) - efi_64 = true; -else if (et ==EFI_TYPE_32 ) - efi_64 = false; -else +if (et ==EFI_TYPE_NONE )return 0 ; systab_pa =efi_get_system_table (boot_params);
@@ -142,7 +120,7 @@ static acpi_physical_address efi_get_rsdp_addr(void)if (ret || !cfg_tbl_pa)error ("EFI config table not found." ); -return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len, efi_64); +return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len);#else return 0 ;#endif
arch/x86/boot/compressed/efi.c +72 -0
75 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +13 -0
@@ -23,6 +23,7 @@#include <linux/screen_info.h> #include <linux/elf.h> #include <linux/io.h> +#include <linux/efi.h> #include <asm/page.h> #include <asm/boot.h> #include <asm/bootparam.h>
@@ -188,6 +189,10 @@ enum efi_type efi_get_type(struct boot_params *bp);unsigned long efi_get_system_table (struct boot_params *bp);int efi_get_conf_table (struct boot_params *bp,unsigned long *cfg_tbl_pa,unsigned int *cfg_tbl_len); +unsigned long efi_find_vendor_table (struct boot_params *bp, +unsigned long cfg_tbl_pa, +unsigned int cfg_tbl_len, +efi_guid_t guid);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {
@@ -205,6 +210,14 @@ static inline int efi_get_conf_table(struct boot_params *bp, {return -ENOENT ; } + +static inline unsigned long efi_find_vendor_table (struct boot_params *bp, +unsigned long cfg_tbl_pa, +unsigned int cfg_tbl_len, +efi_guid_t guid) +{ +return 0 ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/acpi: Move EFI vendor table lookup to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: dee602dd5d1489b5aa4651c561dfbe90eaee1589 Gitweb: https://git.kernel.org/tip/dee602dd5d1489b5aa4651c561dfbe90eaee1589 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:07 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:07:19 +02:00
x86/compressed/acpi: Move EFI vendor table lookup to helper
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
[ bp: Unbreak unnecessarily broken lines. ]
--- arch/x86/boot/compressed/acpi.c | 68 ++++++++++--------------------- arch/x86/boot/compressed/efi.c | 70 ++++++++++++++++++++++++++++++++- arch/x86/boot/compressed/misc.h | 13 ++++++- 3 files changed, 106 insertions(+), 45 deletions(-)
arch/x86/boot/compressed/acpi.c +23 -45
@@ -20,48 +20,31 @@*/ struct mem_vector immovable_mem[MAX_NUMNODES *2 ]; -/* -* Search EFI system tables for RSDP. If both ACPI_20_TABLE_GUID and -* ACPI_TABLE_GUID are found, take the former, which has more features. -*/ static acpi_physical_address -__efi_get_rsdp_addr (unsigned long config_tables,unsigned int nr_tables, -bool efi_64) +__efi_get_rsdp_addr (unsigned long cfg_tbl_pa,unsigned int cfg_tbl_len) { -acpi_physical_address rsdp_addr =0 ; -#ifdef CONFIG_EFI -int i; - -/* Get EFI tables from systab. */ -for (i =0 ; i < nr_tables; i++) { -acpi_physical_address table; -efi_guid_t guid; - -if (efi_64) { -efi_config_table_64_t *tbl = (efi_config_table_64_t *)config_tables + i; - - guid = tbl->guid; - table = tbl->table; - -if (!IS_ENABLED (CONFIG_X86_64 ) && table >>32 ) { -debug_putstr ("Error getting RSDP address: EFI config table located above 4GB.\n" ); -return 0 ; - } - }else { -efi_config_table_32_t *tbl = (efi_config_table_32_t *)config_tables + i; - - guid = tbl->guid; - table = tbl->table; - } +unsigned long rsdp_addr; +int ret; -if (!(efi_guidcmp (guid,ACPI_TABLE_GUID ))) - rsdp_addr = table; -else if (!(efi_guidcmp (guid,ACPI_20_TABLE_GUID ))) -return table; - } +/* +* Search EFI system tables for RSDP. Preferred is ACPI_20_TABLE_GUID to +* ACPI_TABLE_GUID because it has more features. +*/ + rsdp_addr =efi_find_vendor_table (boot_params, cfg_tbl_pa, cfg_tbl_len, +ACPI_20_TABLE_GUID ); +if (rsdp_addr) +return (acpi_physical_address )rsdp_addr; + +/* No ACPI_20_TABLE_GUID found, fallback to ACPI_TABLE_GUID. */ + rsdp_addr =efi_find_vendor_table (boot_params, cfg_tbl_pa, cfg_tbl_len, +ACPI_TABLE_GUID ); +if (rsdp_addr) +return (acpi_physical_address )rsdp_addr; + +debug_putstr ("Error getting RSDP address.\n" );#endif -return rsdp_addr; +return 0 ; }/* EFI/kexec support is 64-bit only. */
@@ -109,7 +92,7 @@ static acpi_physical_address kexec_get_rsdp_addr(void)if (!systab)error ("EFI system table not found in kexec boot_params." ); - return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables, true); + return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables); }#else static acpi_physical_address kexec_get_rsdp_addr (void ) {return 0 ; }
@@ -123,15 +106,10 @@ static acpi_physical_address efi_get_rsdp_addr(void)unsigned long systab_pa;unsigned int nr_tables;enum efi_type et; -bool efi_64;int ret; et =efi_get_type (boot_params); -if (et ==EFI_TYPE_64 ) - efi_64 = true; -else if (et ==EFI_TYPE_32 ) - efi_64 = false; -else +if (et ==EFI_TYPE_NONE )return 0 ; systab_pa =efi_get_system_table (boot_params);
@@ -142,7 +120,7 @@ static acpi_physical_address efi_get_rsdp_addr(void)if (ret || !cfg_tbl_pa)error ("EFI config table not found." ); -return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len, efi_64); +return __efi_get_rsdp_addr (cfg_tbl_pa, cfg_tbl_len);#else return 0 ;#endif
arch/x86/boot/compressed/efi.c +70 -0
73 lines not on this page · raw message
arch/x86/boot/compressed/misc.h +13 -0
@@ -23,6 +23,7 @@#include <linux/screen_info.h> #include <linux/elf.h> #include <linux/io.h> +#include <linux/efi.h> #include <asm/page.h> #include <asm/boot.h> #include <asm/bootparam.h>
@@ -188,6 +189,10 @@ enum efi_type efi_get_type(struct boot_params *bp);unsigned long efi_get_system_table (struct boot_params *bp);int efi_get_conf_table (struct boot_params *bp,unsigned long *cfg_tbl_pa,unsigned int *cfg_tbl_len); +unsigned long efi_find_vendor_table (struct boot_params *bp, +unsigned long cfg_tbl_pa, +unsigned int cfg_tbl_len, +efi_guid_t guid);#else static inline enum efi_type efi_get_type (struct boot_params *bp) {
@@ -205,6 +210,14 @@ static inline int efi_get_conf_table(struct boot_params *bp, {return -ENOENT ; } + +static inline unsigned long efi_find_vendor_table (struct boot_params *bp, +unsigned long cfg_tbl_pa, +unsigned int cfg_tbl_len, +efi_guid_t guid) +{ +return 0 ; +}#endif /* CONFIG_EFI */ #endif /* BOOT_COMPRESSED_MISC_H */
PATCH v12 28/46 x86/compressed/acpi: Move EFI kexec handling into common code
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
In this instance, the current acpi.c kexec handling is mainly used to get the alternative EFI config table address provided by kexec via a setup_data entry of type SETUP_EFI. If not present, the code then falls back to normal EFI config table address provided by EFI system table. This would need to be done by all call-sites attempting to access the EFI config table, so just have efi_get_conf_table() handle that automatically.
--- arch/x86/boot/compressed/acpi.c | 59 --------------------------------- arch/x86/boot/compressed/efi.c | 46 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 60 deletions(-)
arch/x86/boot/compressed/acpi.c +0 -59
@@ -47,57 +47,6 @@ __efi_get_rsdp_addr(unsigned long cfg_tbl_pa, unsigned int cfg_tbl_len)return 0 ; } -/* EFI/kexec support is 64-bit only. */ -#ifdef CONFIG_X86_64 -static struct efi_setup_data *get_kexec_setup_data_addr (void ) -{ -struct setup_data *data; -u64 pa_data; - - pa_data = boot_params->hdr.setup_data; -while (pa_data) { - data = (struct setup_data *)pa_data; -if (data->type ==SETUP_EFI ) -return (struct efi_setup_data *)(pa_data +sizeof (struct setup_data )); - - pa_data = data->next; - } -return NULL ; -} - -static acpi_physical_address kexec_get_rsdp_addr (void ) -{ -efi_system_table_64_t *systab; -struct efi_setup_data *esd; -struct efi_info *ei; -enum efi_type et; - - esd = (struct efi_setup_data *)get_kexec_setup_data_addr (); -if (!esd) -return 0 ; - -if (!esd->tables) { -debug_putstr ("Wrong kexec SETUP_EFI data.\n" ); -return 0 ; - } - - et =efi_get_type (boot_params); -if (et !=EFI_TYPE_64 ) { -debug_putstr ("Unexpected kexec EFI environment (expected 64-bit EFI).\n" ); -return 0 ; - } - -/* Get systab from boot params. */ - systab = (efi_system_table_64_t *)efi_get_system_table (boot_params); -if (!systab) -error ("EFI system table not found in kexec boot_params." ); - -return __efi_get_rsdp_addr ((unsigned long )esd->tables, systab->nr_tables); -} -#else -static acpi_physical_address kexec_get_rsdp_addr (void ) {return 0 ; } -#endif /* CONFIG_X86_64 */ -static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI
@@ -210,14 +159,6 @@ acpi_physical_address get_rsdp_addr(void) pa = boot_params->acpi_rsdp_addr; -/* -* Try to get EFI data from setup_data. This can happen when we're a -* kexec'ed kernel and kexec(1) has passed all the required EFI info to -* us. -*/ -if (!pa) - pa =kexec_get_rsdp_addr (); -if (!pa) pa =efi_get_rsdp_addr ();
arch/x86/boot/compressed/efi.c +45 -1
59 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/acpi: Move EFI kexec handling into common code
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 824f37783189a48db914488fb41eba36ec57ebb7 Gitweb: https://git.kernel.org/tip/824f37783189a48db914488fb41eba36ec57ebb7 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:08 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Wed, 06 Apr 2022 17:07:24 +02:00
x86/compressed/acpi: Move EFI kexec handling into common code
Future patches for SEV-SNP-validated CPUID will also require early parsing of the EFI configuration. Incrementally move the related code into a set of helpers that can be re-used for that purpose.
In this instance, the current acpi.c kexec handling is mainly used to get the alternative EFI config table address provided by kexec via a setup_data entry of type SETUP_EFI. If not present, the code then falls back to normal EFI config table address provided by EFI system table. This would need to be done by all call-sites attempting to access the EFI config table, so just have efi_get_conf_table() handle that automatically.
--- arch/x86/boot/compressed/acpi.c | 59 +-------------------------------- arch/x86/boot/compressed/efi.c | 46 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 60 deletions(-)
arch/x86/boot/compressed/acpi.c +0 -59
@@ -47,57 +47,6 @@ __efi_get_rsdp_addr(unsigned long cfg_tbl_pa, unsigned int cfg_tbl_len)return 0 ; } -/* EFI/kexec support is 64-bit only. */ -#ifdef CONFIG_X86_64 -static struct efi_setup_data *get_kexec_setup_data_addr (void ) -{ -struct setup_data *data; -u64 pa_data; - - pa_data = boot_params->hdr.setup_data; -while (pa_data) { - data = (struct setup_data *)pa_data; -if (data->type ==SETUP_EFI ) -return (struct efi_setup_data *)(pa_data +sizeof (struct setup_data )); - - pa_data = data->next; - } -return NULL ; -} - -static acpi_physical_address kexec_get_rsdp_addr (void ) -{ -efi_system_table_64_t *systab; -struct efi_setup_data *esd; -struct efi_info *ei; -enum efi_type et; - - esd = (struct efi_setup_data *)get_kexec_setup_data_addr (); -if (!esd) -return 0 ; - -if (!esd->tables) { -debug_putstr ("Wrong kexec SETUP_EFI data.\n" ); -return 0 ; - } - - et =efi_get_type (boot_params); -if (et !=EFI_TYPE_64 ) { -debug_putstr ("Unexpected kexec EFI environment (expected 64-bit EFI).\n" ); -return 0 ; - } - -/* Get systab from boot params. */ - systab = (efi_system_table_64_t *)efi_get_system_table (boot_params); -if (!systab) -error ("EFI system table not found in kexec boot_params." ); - -return __efi_get_rsdp_addr ((unsigned long )esd->tables, systab->nr_tables); -} -#else -static acpi_physical_address kexec_get_rsdp_addr (void ) {return 0 ; } -#endif /* CONFIG_X86_64 */ -static acpi_physical_address efi_get_rsdp_addr (void ) {#ifdef CONFIG_EFI
@@ -210,14 +159,6 @@ acpi_physical_address get_rsdp_addr(void) pa = boot_params->acpi_rsdp_addr; -/* -* Try to get EFI data from setup_data. This can happen when we're a -* kexec'ed kernel and kexec(1) has passed all the required EFI info to -* us. -*/ -if (!pa) - pa =kexec_get_rsdp_addr (); -if (!pa) pa =efi_get_rsdp_addr ();
arch/x86/boot/compressed/efi.c +45 -1
59 lines not on this page · raw message
PATCH v12 29/46 x86/boot: Add Confidential Computing type to setup_data
In reply to Brijesh SinghWhile launching the encrypted guests, the hypervisor may need to provide some additional information during the guest boot. When booting under the EFI based BIOS, the EFI configuration table contains an entry for the confidential computing blob that contains the required information.
To support booting encrypted guests on non-EFI VM, the hypervisor needs to pass this additional information to the kernel with a different method.
For this purpose, introduce SETUP_CC_BLOB type in setup_data to hold the physical address of the confidential computing blob location. The boot loader or hypervisor may choose to use this method instead of EFI configuration table. The CC blob location scanning should give preference to setup_data data over the EFI configuration table.
In AMD SEV-SNP, the CC blob contains the address of the secrets and CPUID pages. The secrets page includes information such as a VM to PSP communication key and CPUID page contains PSP filtered CPUID values. Define the AMD SEV confidential computing blob structure.
While at it, define the EFI GUID for the confidential computing blob.
--- arch/x86/include/asm/sev.h | 18 ++++++++++++++++++ arch/x86/include/uapi/asm/bootparam.h | 1 + include/linux/efi.h | 1 + 3 files changed, 20 insertions(+)
arch/x86/include/asm/sev.h +18 -0
@@ -42,6 +42,24 @@ struct es_em_ctxt {struct es_fault_info fi; }; +/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info { +u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys; +u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +}; +void do_vc_no_ghcb (struct pt_regs *regs,unsigned long exit_code);static inline u64 lower_bits (u64 val,unsigned int bits)
arch/x86/include/uapi/asm/bootparam.h +1 -0
@@ -10,6 +10,7 @@#define SETUP_EFI 4#define SETUP_APPLE_PROPERTIES 5#define SETUP_JAILHOUSE 6 +#define SETUP_CC_BLOB 7#define SETUP_INDIRECT (1<<31)
include/linux/efi.h +1 -0
@@ -390,6 +390,7 @@ void efi_native_runtime_setup(void);#define EFI_CERT_SHA256_GUID EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)#define EFI_CERT_X509_GUID EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)#define EFI_CERT_X509_SHA256_GUID EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) +#define EFI_CC_BLOB_GUID EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)/* * This GUID is used to pass to the kernel proper the struct screen_info
Signature · 1 line
2.25.1
Re: [PATCH v12 29/46] x86/boot: Add Confidential Computing type to setup_data
Quoted 8 lines · Brijesh Singh
arch/x86/include/asm/sev.h +7
-0+/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info {
arch/x86/include/asm/sev.h struct es_em_ctxt { · line 61
Quoted 10 lines
arch/x86/include/asm/sev.h +10
-0+u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys; +u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +};
Shouldn't this be packed?
Thanks,
tglx
Re: [PATCH v12 29/46] x86/boot: Add Confidential Computing type to setup_data
Quoted 13 lines · Thomas Gleixner
Quoted 12 lines · Brijesh Singh
arch/x86/include/asm/sev.h +11
-0+/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info { +u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys;
Quoted 8 lines
arch/x86/include/asm/sev.h struct es_em_ctxt { · line 61
Quoted 6 lines
arch/x86/include/asm/sev.h +6
-0+u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +};Shouldn't this be packed?
Done.
Thx.
Signature · 4 lines
Regards/Gruss,
Boris.
SUSE Software Solutions Germany GmbH, GF: Ivo Totev, HRB 36809, AG NürnbergRe: [PATCH v12 29/46] x86/boot: Add Confidential Computing type to setup_data
In reply to Thomas GleixnerQuoted 13 lines · Thomas Gleixner
Quoted 12 lines · Brijesh Singh
arch/x86/include/asm/sev.h +11
-0+/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info { +u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys;
Quoted 9 lines
arch/x86/include/asm/sev.h struct es_em_ctxt { · line 61
Quoted 6 lines
arch/x86/include/asm/sev.h +6
-0+u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +};Shouldn't this be packed?
Yep, to avoid any additional compiler alignment we should pack it.
thanks
H. Peter Anvin
reviewerRe: [PATCH v12 29/46] x86/boot: Add Confidential Computing type to setup_data
Quoted 26 lines · Brijesh Singh
Quoted 13 lines · Thomas Gleixner
Quoted 12 lines · Brijesh Singh
arch/x86/include/asm/sev.h +11
-0+/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info { +u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys;Quoted 9 lines
arch/x86/include/asm/sev.h struct es_em_ctxt { · line 61
Quoted 6 lines
arch/x86/include/asm/sev.h +6
-0+u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +};Shouldn't this be packed?
Quoted 3 lines
Yep, to avoid any additional compiler alignment we should pack it.
thanks
It shouldn't be *necessary*, any more than it is necessary for kernel-user space structures, since EFI is a C-based ABI. On x86 it doesn't hurt, either, though, so might as well.
[tip: x86/sev] x86/boot: Add Confidential Computing type to setup_data
In reply to Brijesh SinghThe following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 5ea98e01ab524cbc53dad8aebd27b434ebe5d074 Gitweb: https://git.kernel.org/tip/5ea98e01ab524cbc53dad8aebd27b434ebe5d074 Author: Brijesh Singh <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:39 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:46:33 +02:00
x86/boot: Add Confidential Computing type to setup_data
While launching encrypted guests, the hypervisor may need to provide some additional information during the guest boot. When booting under an EFI-based BIOS, the EFI configuration table contains an entry for the confidential computing blob that contains the required information.
To support booting encrypted guests on non-EFI VMs, the hypervisor needs to pass this additional information to the guest kernel using a different method.
For this purpose, introduce SETUP_CC_BLOB type in setup_data to hold the physical address of the confidential computing blob location. The boot loader or hypervisor may choose to use this method instead of an EFI configuration table. The CC blob location scanning should give preference to a setup_data blob over an EFI configuration table.
In AMD SEV-SNP, the CC blob contains the address of the secrets and CPUID pages. The secrets page includes information such as a VM to PSP communication key and the CPUID page contains PSP-filtered CPUID values. Define the AMD SEV confidential computing blob structure.
While at it, define the EFI GUID for the confidential computing blob.
[ bp: Massage commit message, mark struct __packed. ]
--- arch/x86/include/asm/sev.h | 18 ++++++++++++++++++ arch/x86/include/uapi/asm/bootparam.h | 1 + include/linux/efi.h | 1 + 3 files changed, 20 insertions(+)
arch/x86/include/asm/sev.h +18 -0
@@ -42,6 +42,24 @@ struct es_em_ctxt {struct es_fault_info fi; }; +/* +* AMD SEV Confidential computing blob structure. The structure is +* defined in OVMF UEFI firmware header: +* https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Guid/ConfidentialComputingSevSnpBlob.h +*/ +#define CC_BLOB_SEV_HDR_MAGIC 0x45444d41 +struct cc_blob_sev_info { +u32 magic; +u16 version; +u16 reserved; +u64 secrets_phys; +u32 secrets_len; +u32 rsvd1; +u64 cpuid_phys; +u32 cpuid_len; +u32 rsvd2; +} __packed; +void do_vc_no_ghcb (struct pt_regs *regs,unsigned long exit_code);static inline u64 lower_bits (u64 val,unsigned int bits)
arch/x86/include/uapi/asm/bootparam.h +1 -0
@@ -10,6 +10,7 @@#define SETUP_EFI 4#define SETUP_APPLE_PROPERTIES 5#define SETUP_JAILHOUSE 6 +#define SETUP_CC_BLOB 7#define SETUP_INDIRECT (1<<31)
include/linux/efi.h +1 -0
@@ -390,6 +390,7 @@ void efi_native_runtime_setup(void);#define EFI_CERT_SHA256_GUID EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)#define EFI_CERT_X509_GUID EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)#define EFI_CERT_X509_SHA256_GUID EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) +#define EFI_CC_BLOB_GUID EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42)/* * This GUID is used to pass to the kernel proper the struct screen_info
PATCH v12 30/46 KVM: x86: Move lookup of indexed CPUID leafs to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Determining which CPUID leafs have significant ECX/index values is also needed by guest kernel code when doing SEV-SNP-validated CPUID lookups. Move this to common code to keep future updates in sync.
--- arch/x86/include/asm/cpuid.h | 34 ++++++++++++++++++++++++++++++++++ arch/x86/kvm/cpuid.c | 19 ++----------------- 2 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 arch/x86/include/asm/cpuid.h
arch/x86/include/asm/cpuid.h new file +34 -0
@@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* CPUID-related helpers/definitions +* +* Derived from arch/x86/kvm/cpuid.c +*/ + +#ifndef _ASM_X86_CPUID_H +#define _ASM_X86_CPUID_H + +static __always_inline bool cpuid_function_is_indexed(u32 function) +{ +switch (function) { +case 4 : +case 7 : +case 0xb : +case 0xd : +case 0xf : +case 0x10 : +case 0x12 : +case 0x14 : +case 0x17 : +case 0x18 : +case 0x1d : +case 0x1e : +case 0x1f : +case 0x8000001d : +return true; + } + +return false; +} + +#endif /* _ASM_X86_CPUID_H */
arch/x86/kvm/cpuid.c +2 -17
@@ -19,6 +19,7 @@#include <asm/user.h> #include <asm/fpu/xstate.h> #include <asm/sgx.h> +#include <asm/cpuid.h> #include "cpuid.h" #include "lapic.h" #include "mmu.h"
@@ -722,24 +723,8 @@ static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,cpuid_count (entry->function, entry->index, &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); -switch (function) { -case 4 : -case 7 : -case 0xb : -case 0xd : -case 0xf : -case 0x10 : -case 0x12 : -case 0x14 : -case 0x17 : -case 0x18 : -case 0x1d : -case 0x1e : -case 0x1f : -case 0x8000001d : +if (cpuid_function_is_indexed (function)) entry->flags |=KVM_CPUID_FLAG_SIGNIFCANT_INDEX ; -break ; - }return entry; }
Signature · 1 line
2.25.1
[tip: x86/sev] KVM: x86: Move lookup of indexed CPUID leafs to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: b66370db9a90b3fa4c4a1a732af3e7e38d6d4c7c Gitweb: https://git.kernel.org/tip/b66370db9a90b3fa4c4a1a732af3e7e38d6d4c7c Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:10 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
KVM: x86: Move lookup of indexed CPUID leafs to helper
Determining which CPUID leafs have significant ECX/index values is also needed by guest kernel code when doing SEV-SNP-validated CPUID lookups. Move this to common code to keep future updates in sync.
--- arch/x86/include/asm/cpuid.h | 34 ++++++++++++++++++++++++++++++++++ arch/x86/kvm/cpuid.c | 19 ++----------------- 2 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 arch/x86/include/asm/cpuid.h
arch/x86/include/asm/cpuid.h new file +34 -0
@@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* CPUID-related helpers/definitions +* +* Derived from arch/x86/kvm/cpuid.c +*/ + +#ifndef _ASM_X86_CPUID_H +#define _ASM_X86_CPUID_H + +static __always_inline bool cpuid_function_is_indexed(u32 function) +{ +switch (function) { +case 4 : +case 7 : +case 0xb : +case 0xd : +case 0xf : +case 0x10 : +case 0x12 : +case 0x14 : +case 0x17 : +case 0x18 : +case 0x1d : +case 0x1e : +case 0x1f : +case 0x8000001d : +return true; + } + +return false; +} + +#endif /* _ASM_X86_CPUID_H */
arch/x86/kvm/cpuid.c +2 -17
@@ -19,6 +19,7 @@#include <asm/user.h> #include <asm/fpu/xstate.h> #include <asm/sgx.h> +#include <asm/cpuid.h> #include "cpuid.h" #include "lapic.h" #include "mmu.h"
@@ -744,24 +745,8 @@ static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,cpuid_count (entry->function, entry->index, &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); -switch (function) { -case 4 : -case 7 : -case 0xb : -case 0xd : -case 0xf : -case 0x10 : -case 0x12 : -case 0x14 : -case 0x17 : -case 0x18 : -case 0x1d : -case 0x1e : -case 0x1f : -case 0x8000001d : +if (cpuid_function_is_indexed (function)) entry->flags |=KVM_CPUID_FLAG_SIGNIFCANT_INDEX ; -break ; - }return entry; }
PATCH v12 31/46 x86/sev: Move MSR-based VMGEXITs for CPUID to helper
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
This code will also be used later for SEV-SNP-validated CPUID code in some cases, so move it to a common helper.
While here, also add a check to terminate in cases where the CPUID function/subfunction is indexed and the subfunction is non-zero, since the GHCB MSR protocol does not support non-zero subfunctions.
--- arch/x86/boot/compressed/sev.c | 1 + arch/x86/kernel/sev-shared.c | 83 +++++++++++++++++++++++----------- arch/x86/kernel/sev.c | 1 + 3 files changed, 59 insertions(+), 26 deletions(-)
arch/x86/boot/compressed/sev.c +1 -0
@@ -20,6 +20,7 @@#include <asm/fpu/xcr.h> #include <asm/ptrace.h> #include <asm/svm.h> +#include <asm/cpuid.h> #include "error.h" #include "../msr.h"
arch/x86/kernel/sev-shared.c +57 -26
109 lines not on this page · raw message
arch/x86/kernel/sev.c +1 -0
@@ -33,6 +33,7 @@#include <asm/smp.h> #include <asm/cpu.h> #include <asm/apic.h> +#include <asm/cpuid.h> #define DR7_RESET_VALUE 0x400
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Move MSR-based VMGEXITs for CPUID to helper
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 801baa693c1f6d7327475c39100c456db340cd3e Gitweb: https://git.kernel.org/tip/801baa693c1f6d7327475c39100c456db340cd3e Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:11 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/sev: Move MSR-based VMGEXITs for CPUID to helper
This code will also be used later for SEV-SNP-validated CPUID code in some cases, so move it to a common helper.
While here, also add a check to terminate in cases where the CPUID function/subfunction is indexed and the subfunction is non-zero, since the GHCB MSR protocol does not support non-zero subfunctions.
--- arch/x86/boot/compressed/sev.c | 1 +- arch/x86/kernel/sev-shared.c | 83 ++++++++++++++++++++++----------- arch/x86/kernel/sev.c | 1 +- 3 files changed, 59 insertions(+), 26 deletions(-)
arch/x86/boot/compressed/sev.c +1 -0
@@ -20,6 +20,7 @@#include <asm/fpu/xcr.h> #include <asm/ptrace.h> #include <asm/svm.h> +#include <asm/cpuid.h> #include "error.h" #include "../msr.h"
arch/x86/kernel/sev-shared.c +57 -26
109 lines not on this page · raw message
arch/x86/kernel/sev.c +1 -0
@@ -33,6 +33,7 @@#include <asm/smp.h> #include <asm/cpu.h> #include <asm/apic.h> +#include <asm/cpuid.h> #define DR7_RESET_VALUE 0x400
PATCH v12 32/46 x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
CPUID instructions generate a #VC exception for SEV-ES/SEV-SNP guests, for which early handlers are currently set up to handle. In the case of SEV-SNP, guests can use a configurable location in guest memory that has been pre-populated with a firmware-validated CPUID table to look up the relevant CPUID values rather than requesting them from hypervisor via a VMGEXIT. Add the various hooks in the #VC handlers to allow CPUID instructions to be handled via the table. The code to actually configure/enable the table will be added in a subsequent commit.
--- arch/x86/include/asm/sev-common.h | 2 + arch/x86/kernel/sev-shared.c | 324 ++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+)
arch/x86/include/asm/sev-common.h +2 -0
@@ -152,6 +152,8 @@ struct snp_psc_desc {#define GHCB_TERM_PSC 1/* Page State Change failure */ #define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ #define GHCB_TERM_NOT_VMPL0 3/* SNP guest is not running at VMPL-0 */ +#define GHCB_TERM_CPUID 4/* CPUID-validation failure */ +#define GHCB_TERM_CPUID_HV 5/* CPUID failure during hypervisor fallback */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/kernel/sev-shared.c +324 -0
369 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
()
Quoted 264 lines · Brijesh Singh
From: Michael Roth <[email protected]>
CPUID instructions generate a #VC exception for SEV-ES/SEV-SNP guests, for which early handlers are currently set up to handle. In the case of SEV-SNP, guests can use a configurable location in guest memory that has been pre-populated with a firmware-validated CPUID table to look up the relevant CPUID values rather than requesting them from hypervisor via a VMGEXIT. Add the various hooks in the #VC handlers to allow CPUID instructions to be handled via the table. The code to actually configure/enable the table will be added in a subsequent commit.
Signed-off-by Michael Roth <[email protected]>Signed-off-by Brijesh Singh <[email protected]>--- arch/x86/include/asm/sev-common.h | 2 + arch/x86/kernel/sev-shared.c | 324 ++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+)arch/x86/include/asm/sev-common.h +2
-0@@ -152,6 +152,8 @@ struct snp_psc_desc {#define GHCB_TERM_PSC 1/* Page State Change failure */ #define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ #define GHCB_TERM_NOT_VMPL0 3/* SNP guest is not running at VMPL-0 */ +#define GHCB_TERM_CPUID 4/* CPUID-validation failure */ +#define GHCB_TERM_CPUID_HV 5/* CPUID failure during hypervisor fallback */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)arch/x86/kernel/sev-shared.c +209
-0@@ -24,6 +24,36 @@ struct cpuid_leaf {u32 edx; }; +/* +* Individual entries of the SNP CPUID table, as defined by the SNP +* Firmware ABI, Revision 0.9, Section 7.1, Table 14. +*/ +struct snp_cpuid_fn { +u32 eax_in; +u32 ecx_in; +u64 xcr0_in; +u64 xss_in; +u32 eax; +u32 ebx; +u32 ecx; +u32 edx; +u64 __reserved; +} __packed; + +/* +* SNP CPUID table, as defined by the SNP Firmware ABI, Revision 0.9, +* Section 8.14.2.6. Also noted there is the SNP firmware-enforced limit +* of 64 entries per CPUID table. +*/ +#define SNP_CPUID_COUNT_MAX 64 + +struct snp_cpuid_table { +u32 count; +u32 __reserved1; +u64 __reserved2; +struct snp_cpuid_fn fn[SNP_CPUID_COUNT_MAX ]; +} __packed; +/* * Since feature negotiation related variables are set early in the boot * process they must reside in the .data section so as not to be zeroed @@ -33,6 +63,19 @@ struct cpuid_leaf {*/ static u16 ghcb_version__ro_after_init ; +/* Copy of the SNP firmware's CPUID page. */ +static struct snp_cpuid_table cpuid_table_copy__ro_after_init ; + +/* +* These will be initialized based on CPUID table so that non-present +* all-zero leaves (for sparse tables) can be differentiated from +* invalid/out-of-range leaves. This is needed since all-zero leaves +* still need to be post-processed. +*/ +static u32 cpuid_std_range_max__ro_after_init ; +static u32 cpuid_hyp_range_max__ro_after_init ; +static u32 cpuid_ext_range_max__ro_after_init ; +static bool __init sev_es_check_cpu_features (void ) {if (!has_cpuflag (X86_FEATURE_RDRAND )) {@@ -242,6 +285,252 @@ static int sev_cpuid_hv(struct cpuid_leaf *leaf)return ret; } +/* +* This may be called early while still running on the initial identity +* mapping. Use RIP-relative addressing to obtain the correct address +* while running with the initial identity mapping as well as the +* switch-over to kernel virtual addresses later. +*/ +static const struct snp_cpuid_table *snp_cpuid_get_table (void ) +{ +void *ptr; + + asm ("lea cpuid_table_copy(%%rip), %0" + :"=r" (ptr) + :"p" (&cpuid_table_copy)); + +return ptr; +} + +/* +* The SNP Firmware ABI, Revision 0.9, Section 7.1, details the use of +* XCR0_IN and XSS_IN to encode multiple versions of 0xD subfunctions 0 +* and 1 based on the corresponding features enabled by a particular +* combination of XCR0 and XSS registers so that a guest can look up the +* version corresponding to the features currently enabled in its XCR0/XSS +* registers. The only values that differ between these versions/table +* entries is the enabled XSAVE area size advertised via EBX. +* +* While hypervisors may choose to make use of this support, it is more +* robust/secure for a guest to simply find the entry corresponding to the +* base/legacy XSAVE area size (XCR0=1 or XCR0=3), and then calculate the +* XSAVE area size using subfunctions 2 through 64, as documented in APM +* Volume 3, Rev 3.31, Appendix E.3.8, which is what is done here. +* +* Since base/legacy XSAVE area size is documented as 0x240, use that value +* directly rather than relying on the base size in the CPUID table. +* +* Return: XSAVE area size on success, 0 otherwise. +*/ +static u32 snp_cpuid_calc_xsave_size (u64 xfeatures_en,bool compacted) +{ +const struct snp_cpuid_table *cpuid_table =snp_cpuid_get_table (); +u64 xfeatures_found =0 ; +u32 xsave_size =0x240 ; +int i; + +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *e = &cpuid_table->fn[i]; + +if (!(e->eax_in ==0xD && e->ecx_in >1 && e->ecx_in <64 )) +continue ; +if (!(xfeatures_en & (BIT_ULL (e->ecx_in)))) +continue ; +if (xfeatures_found & (BIT_ULL (e->ecx_in))) +continue ; + + xfeatures_found |= (BIT_ULL (e->ecx_in)); + +if (compacted) + xsave_size += e->eax; +else + xsave_size =max (xsave_size, e->eax + e->ebx); + } + +/* +* Either the guest set unsupported XCR0/XSS bits, or the corresponding +* entries in the CPUID table were not present. This is not a valid +* state to be in. +*/ +if (xfeatures_found != (xfeatures_en &GENMASK_ULL (63 ,2 ))) +return 0 ; + +return xsave_size; +} + +static bool +snp_cpuid_get_validated_func (struct cpuid_leaf *leaf) +{ +const struct snp_cpuid_table *cpuid_table =snp_cpuid_get_table (); +int i; + +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *e = &cpuid_table->fn[i]; + +if (e->eax_in != leaf->fn) +continue ; + +if (cpuid_function_is_indexed (leaf->fn) && e->ecx_in != leaf->subfn) +continue ; + +/* +* For 0xD subfunctions 0 and 1, only use the entry corresponding +* to the base/legacy XSAVE area size (XCR0=1 or XCR0=3, XSS=0). +* See the comments above snp_cpuid_calc_xsave_size() for more +* details. +*/ +if (e->eax_in ==0xD && (e->ecx_in ==0 || e->ecx_in ==1 )) +if (!(e->xcr0_in ==1 || e->xcr0_in ==3 ) || e->xss_in) +continue ; + + leaf->eax = e->eax; + leaf->ebx = e->ebx; + leaf->ecx = e->ecx; + leaf->edx = e->edx; + +return true; + } + +return false; +} + +static void snp_cpuid_hv (struct cpuid_leaf *leaf) +{ +if (sev_cpuid_hv (leaf)) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID_HV ); +} + +static int snp_cpuid_postprocess (struct cpuid_leaf *leaf) +{ +struct cpuid_leaf leaf_hv = *leaf; + +switch (leaf->fn) { +case 0x1 : +snp_cpuid_hv (&leaf_hv); + +/* initial APIC ID */ + leaf->ebx = (leaf_hv.ebx &GENMASK (31 ,24 )) | (leaf->ebx &GENMASK (23 ,0 )); +/* APIC enabled bit */ + leaf->edx = (leaf_hv.edx &BIT (9 )) | (leaf->edx & ~BIT (9 )); + +/* OSXSAVE enabled bit */ +if (native_read_cr4 () &X86_CR4_OSXSAVE ) + leaf->ecx |=BIT (27 ); +break ; +case 0x7 : +/* OSPKE enabled bit */ + leaf->ecx &= ~BIT (4 ); +if (native_read_cr4 () &X86_CR4_PKE ) + leaf->ecx |=BIT (4 ); +break ; +case 0xB : + leaf_hv.subfn =0 ; +snp_cpuid_hv (&leaf_hv); + +/* extended APIC ID */ + leaf->edx = leaf_hv.edx; +break ; +case 0xD : { +bool compacted = false; +u64 xcr0 =1 , xss =0 ; +u32 xsave_size; + +if (leaf->subfn !=0 && leaf->subfn !=1 ) +return 0 ; + +if (native_read_cr4 () &X86_CR4_OSXSAVE ) + xcr0 =xgetbv (XCR_XFEATURE_ENABLED_MASK ); +if (leaf->subfn ==1 ) { +/* Get XSS value if XSAVES is enabled. */ +if (leaf->eax &BIT (3 )) { +unsigned long lo, hi; + + asmvolatile ("rdmsr" :"=a" (lo),"=d" (hi) + :"c" (MSR_IA32_XSS )); + xss = (hi <<32 ) | lo; + } + +/*
arch/x86/kernel/sev-shared.c static int sev_cpuid_hv(struct cpuid_leaf *leaf) · line 463
Quoted 10 lines
arch/x86/kernel/sev-shared.c +10
-0+* The PPR and APM aren't clear on what size should be +* encoded in 0xD:0x1:EBX when compaction is not enabled +* by either XSAVEC (feature bit 1) or XSAVES (feature +* bit 3) since SNP-capable hardware has these feature +* bits fixed as 1. KVM sets it to 0 in this case, but +* to avoid this becoming an issue it's safer to simply +* treat this as unsupported for SNP guests. +*/ +if (!(leaf->eax & (BIT (1 ) |BIT (3 )))) +return -EINVAL ;
I couldn't get this patch set to boot and I found that I was setting these XSAVE cpuid bits wrong. This took me a while to debug because inside of handle_vc_boot_ghcb() this -EINVAL means we jump into the halt loop, in addition the early_printk()s inside of that function don't seem to be working for me but should the halt in handle_vc_boot_ghcb() be replaced with an sev_es_terminate() or something?
I am still working on why the early_printk()s in that function are not working, it seems that they lead to a different halt. Have you tested any of those error paths manually? For example if you set your CPUID bits to explicitly fail here do you see the expected printks?
Quoted 141 lines
arch/x86/kernel/sev-shared.c +105
-1+ + compacted = true; + } + + xsave_size =snp_cpuid_calc_xsave_size (xcr0 | xss, compacted); +if (!xsave_size) +return -EINVAL ; + + leaf->ebx = xsave_size; + } +break ; +case 0x8000001E : +snp_cpuid_hv (&leaf_hv); + +/* extended APIC ID */ + leaf->eax = leaf_hv.eax; +/* compute ID */ + leaf->ebx = (leaf->ebx &GENMASK (31 ,8 )) | (leaf_hv.ebx &GENMASK (7 ,0 )); +/* node ID */ + leaf->ecx = (leaf->ecx &GENMASK (31 ,8 )) | (leaf_hv.ecx &GENMASK (7 ,0 )); +break ; +default : +/* No fix-ups needed, use values as-is. */ +break ; + } + +return 0 ; +} + +/* +* Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value +* should be treated as fatal by caller. +*/ +static int snp_cpuid (struct cpuid_leaf *leaf) +{ +const struct snp_cpuid_table *cpuid_table =snp_cpuid_get_table (); + +if (!cpuid_table->count) +return -EOPNOTSUPP ; + +if (!snp_cpuid_get_validated_func (leaf)) { +/* +* Some hypervisors will avoid keeping track of CPUID entries +* where all values are zero, since they can be handled the +* same as out-of-range values (all-zero). This is useful here +* as well as it allows virtually all guest configurations to +* work using a single SNP CPUID table. +* +* To allow for this, there is a need to distinguish between +* out-of-range entries and in-range zero entries, since the +* CPUID table entries are only a template that may need to be +* augmented with additional values for things like +* CPU-specific information during post-processing. So if it's +* not in the table, set the values to zero. Then, if they are +* within a valid CPUID range, proceed with post-processing +* using zeros as the initial values. Otherwise, skip +* post-processing and just return zeros immediately. +*/ + leaf->eax = leaf->ebx = leaf->ecx = leaf->edx =0 ; + +/* Skip post-processing for out-of-range zero leafs. */ +if (!(leaf->fn <= cpuid_std_range_max || + (leaf->fn >=0x40000000 && leaf->fn <= cpuid_hyp_range_max) || + (leaf->fn >=0x80000000 && leaf->fn <= cpuid_ext_range_max))) +return 0 ; + } + +return snp_cpuid_postprocess (leaf); +} +/* * Boot VC Handler - This is the first VC handler during boot, there is no GHCB * page yet, so it only supports the MSR based communication with the @@ -252,6 +541,7 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)unsigned int subfn =lower_bits (regs->cx,32 );unsigned int fn =lower_bits (regs->ax,32 );struct cpuid_leaf leaf; +int ret;/* Only CPUID is supported via MSR protocol */ if (exit_code !=SVM_EXIT_CPUID )@@ -259,9 +549,18 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) leaf.fn = fn; leaf.subfn = subfn; + + ret =snp_cpuid (&leaf); +if (!ret) + goto cpuid_done; + +if (ret != -EOPNOTSUPP ) + goto fail; +if (sev_cpuid_hv (&leaf)) goto fail; +cpuid_done: regs->ax = leaf.eax; regs->bx = leaf.ebx; regs->cx = leaf.ecx;@@ -556,12 +855,37 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)return ret; } +static int vc_handle_cpuid_snp (struct pt_regs *regs) +{ +struct cpuid_leaf leaf; +int ret; + + leaf.fn = regs->ax; + leaf.subfn = regs->cx; + ret =snp_cpuid (&leaf); +if (!ret) { + regs->ax = leaf.eax; + regs->bx = leaf.ebx; + regs->cx = leaf.ecx; + regs->dx = leaf.edx; + } + +return ret; +} +static enum es_result vc_handle_cpuid (struct ghcb *ghcb,struct es_em_ctxt *ctxt) {struct pt_regs *regs = ctxt->regs;u32 cr4 =native_read_cr4 ();enum es_result ret; +int snp_cpuid_ret; + + snp_cpuid_ret =vc_handle_cpuid_snp (regs); +if (!snp_cpuid_ret) +return ES_OK ; +if (snp_cpuid_ret != -EOPNOTSUPP ) +return ES_VMM_ERROR ;ghcb_set_rax (ghcb, regs->ax);ghcb_set_rcx (ghcb, regs->cx); --2.25.1
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
Quoted 65 lines · Peter Gonda
()
Quoted 51 lines · Brijesh Singh
arch/x86/kernel/sev-shared.c +51
-0+static int snp_cpuid_postprocess (struct cpuid_leaf *leaf) +{ +struct cpuid_leaf leaf_hv = *leaf; + +switch (leaf->fn) { +case 0x1 : +snp_cpuid_hv (&leaf_hv); + +/* initial APIC ID */ + leaf->ebx = (leaf_hv.ebx &GENMASK (31 ,24 )) | (leaf->ebx &GENMASK (23 ,0 )); +/* APIC enabled bit */ + leaf->edx = (leaf_hv.edx &BIT (9 )) | (leaf->edx & ~BIT (9 )); + +/* OSXSAVE enabled bit */ +if (native_read_cr4 () &X86_CR4_OSXSAVE ) + leaf->ecx |=BIT (27 ); +break ; +case 0x7 : +/* OSPKE enabled bit */ + leaf->ecx &= ~BIT (4 ); +if (native_read_cr4 () &X86_CR4_PKE ) + leaf->ecx |=BIT (4 ); +break ; +case 0xB : + leaf_hv.subfn =0 ; +snp_cpuid_hv (&leaf_hv); + +/* extended APIC ID */ + leaf->edx = leaf_hv.edx; +break ; +case 0xD : { +bool compacted = false; +u64 xcr0 =1 , xss =0 ; +u32 xsave_size; + +if (leaf->subfn !=0 && leaf->subfn !=1 ) +return 0 ; + +if (native_read_cr4 () &X86_CR4_OSXSAVE ) + xcr0 =xgetbv (XCR_XFEATURE_ENABLED_MASK ); +if (leaf->subfn ==1 ) { +/* Get XSS value if XSAVES is enabled. */ +if (leaf->eax &BIT (3 )) { +unsigned long lo, hi; + + asmvolatile ("rdmsr" :"=a" (lo),"=d" (hi) + :"c" (MSR_IA32_XSS )); + xss = (hi <<32 ) | lo; + } + +/* arch/x86/kernel/sev-shared.c static int sev_cpuid_hv(struct cpuid_leaf *leaf) · line 463
Quoted 10 lines
arch/x86/kernel/sev-shared.c +10
-0+* The PPR and APM aren't clear on what size should be +* encoded in 0xD:0x1:EBX when compaction is not enabled +* by either XSAVEC (feature bit 1) or XSAVES (feature +* bit 3) since SNP-capable hardware has these feature +* bits fixed as 1. KVM sets it to 0 in this case, but +* to avoid this becoming an issue it's safer to simply +* treat this as unsupported for SNP guests. +*/ +if (!(leaf->eax & (BIT (1 ) |BIT (3 )))) +return -EINVAL ;
Quoted 7 lines
I couldn't get this patch set to boot and I found that I was setting these XSAVE cpuid bits wrong. This took me a while to debug because inside of
handle_vc_boot_ghcb()this-EINVALmeans we jump into the halt loop, in addition the early_printk()s inside of that function don't seem to be working for me but should the halt inhandle_vc_boot_ghcb()be replaced with ansev_es_terminate()or something?
For consistency, the error is propagated up the stack the same way as with all other individual handlers, and it's up to the current #VC handler function how it wants to handle errors. The other #VC handlers terminate, but this one has used a halt loop since its initial implementation in 2020 (1aa9aa8ee517e).
Joerg, do you have more background on that? Would it make sense, outside of this series, to change it to a terminate? Maybe with a specific set of error codes for ES_{OK,UNSUPPORTED,VMM_ERROR,DECODE_FAILED}?
Quoted 3 lines
I am still working on why the early_printk()s in that function are not working, it seems that they lead to a different halt.
I don't see a different halt. They just don't seem to print anything. (keep in mind you still need to advance the IP or else the guest is still gonna end up spinning here, even if you're removing the halt loop for testing purposes)
Quoted 3 lines
working, it seems that they lead to a different halt. Have you tested any of those error paths manually? For example if you set your CPUID bits to explicitly fail here do you see the expected printks?
I think at that point in the code, when the XSAVE stuff is setup, the console hasn't been enabled yet, so messages would get buffered until they get flushed later (which won't happen since there's halt loop after). I know in some cases devs will dump the log buffer from memory instead to get at the error messages for early failures. (Maybe that's also why Joerg decided to use a halt loop there instead of terminating?)
That said, I did some testing to confirm with earlyprintk=serial|vga and I don't see the error messages even if I modify the #VC handler to allow booting to continue. pr_err() messages however do show up if I drop the halt loop. So maybe pr_err() is more appropriate here? But it doesn't really matter unless you plan on digging into guest memory for the logs.
So maybe reworking the error handling in handle_vc_boot_ghcb() to use sev_es_terminate() might be warranted, but probably worth checking with Joerg first, and should be done as a separate series since it is not SNP-related.
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
Quoted 3 lines · Michael Roth
Joerg, do you have more background on that? Would it make sense, outside of this series, to change it to a terminate? Maybe with a specific set of error codes for ES_{OK,UNSUPPORTED,VMM_ERROR,DECODE_FAILED}?
This seems to be a left over from development of the SEV-ES guest patch-set. I wanted to see whether the VM crashed due to a triple fault or an error in the #VC handler. The halt loop can be replaced by termination request now.
Quoted 7 lines
Quoted 2 lines
I am still working on why the early_printk()s in that function are not working, it seems that they lead to a different halt.
I don't see a different halt. They just don't seem to print anything. (keep in mind you still need to advance the IP or else the guest is still gonna end up spinning here, even if you're removing the halt loop for testing purposes)
The early_printks() also cause #VC exceptions, and if that handling is broken for some reason nothing will be printed.
Quoted 11 lines
Quoted 4 lines
working, it seems that they lead to a different halt. Have you tested any of those error paths manually? For example if you set your CPUID bits to explicitly fail here do you see the expected printks?
I think at that point in the code, when the XSAVE stuff is setup, the console hasn't been enabled yet, so messages would get buffered until they get flushed later (which won't happen since there's halt loop after). I know in some cases devs will dump the log buffer from memory instead to get at the error messages for early failures. (Maybe that's also why Joerg decided to use a halt loop there instead of terminating?)
It is hard to dump the log-buffer from encrypted memory :) But I remember having seen messages from these early_printks under SEV-ES for different bugs. Not sure why they don't appear in this situation.
Quoted 4 lines
So maybe reworking the error handling in
handle_vc_boot_ghcb()to usesev_es_terminate()might be warranted, but probably worth checking with Joerg first, and should be done as a separate series since it is not SNP-related.
I am fine with this change.
Regards,
Signature · 10 lines
Jörg Rödel [email protected] SUSE Software Solutions Germany GmbH Maxfeldstr. 5 90409 Nürnberg Germany (HRB 36809, AG Nürnberg) Geschäftsführer: Ivo Totev
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
Quoted 38 lines · Joerg Roedel
Quoted 3 lines · Michael Roth
Joerg, do you have more background on that? Would it make sense, outside of this series, to change it to a terminate? Maybe with a specific set of error codes for ES_{OK,UNSUPPORTED,VMM_ERROR,DECODE_FAILED}?
This seems to be a left over from development of the SEV-ES guest patch-set. I wanted to see whether the VM crashed due to a triple fault or an error in the #VC handler. The halt loop can be replaced by termination request now.
Quoted 7 lines
Quoted 2 lines
I am still working on why the early_printk()s in that function are not working, it seems that they lead to a different halt.
I don't see a different halt. They just don't seem to print anything. (keep in mind you still need to advance the IP or else the guest is still gonna end up spinning here, even if you're removing the halt loop for testing purposes)
The
early_printks()also cause #VC exceptions, and if that handling is broken for some reason nothing will be printed.Quoted 11 lines
Quoted 4 lines
working, it seems that they lead to a different halt. Have you tested any of those error paths manually? For example if you set your CPUID bits to explicitly fail here do you see the expected printks?
I think at that point in the code, when the XSAVE stuff is setup, the console hasn't been enabled yet, so messages would get buffered until they get flushed later (which won't happen since there's halt loop after). I know in some cases devs will dump the log buffer from memory instead to get at the error messages for early failures. (Maybe that's also why Joerg decided to use a halt loop there instead of terminating?)
It is hard to dump the log-buffer from encrypted memory :) But I remember having seen messages from these
early_printksunder SEV-ES for different bugs. Not sure why they don't appear in this situation.
Quoted 6 lines
Quoted 4 lines
So maybe reworking the error handling in
handle_vc_boot_ghcb()to usesev_es_terminate()might be warranted, but probably worth checking with Joerg first, and should be done as a separate series since it is not SNP-related.I am fine with this change.
I'll send a patch out for that.
I was also thinking about adding a vcpu run exit reason for termination. It would be nice to get a more informative exit reason than -EINVAL in userspace. Thoughts?
Quoted 15 lines
Regards,
--
Jörg Rödel
[email protected]SUSE Software Solutions Germany GmbH
Maxfeldstr. 5
90409 Nürnberg
Germany(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
Quoted 3 lines · Peter Gonda
I was also thinking about adding a vcpu run exit reason for termination. It would be nice to get a more informative exit reason than
-EINVALin userspace. Thoughts?
Absolutely - it should be unambiguously clear why we're terminating.
Signature · 1 line
Sent from a small device: formatting sux and brevity is inevitable.
Re: [PATCH v12 32/46] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
Quoted 10 lines · Boris Petkov
Quoted 3 lines · Peter Gonda
I was also thinking about adding a vcpu run exit reason for termination. It would be nice to get a more informative exit reason than
-EINVALin userspace. Thoughts?Absolutely - it should be unambiguously clear why we're terminating.
--
Sent from a small device: formatting sux and brevity is inevitable.
Great, I can work on that too.
[tip: x86/sev] x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
In reply to Brijesh SinghThe following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: ee0bfa08a345370df28c07288e886abcbaac481f Gitweb: https://git.kernel.org/tip/ee0bfa08a345370df28c07288e886abcbaac481f Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:12 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers
CPUID instructions generate a #VC exception for SEV-ES/SEV-SNP guests, for which early handlers are currently set up to handle. In the case of SEV-SNP, guests can use a configurable location in guest memory that has been pre-populated with a firmware-validated CPUID table to look up the relevant CPUID values rather than requesting them from hypervisor via a VMGEXIT. Add the various hooks in the #VC handlers to allow CPUID instructions to be handled via the table. The code to actually configure/enable the table will be added in a subsequent commit.
--- arch/x86/include/asm/sev-common.h | 2 +- arch/x86/kernel/sev-shared.c | 324 +++++++++++++++++++++++++++++- 2 files changed, 326 insertions(+)
arch/x86/include/asm/sev-common.h +2 -0
@@ -152,6 +152,8 @@ struct snp_psc_desc {#define GHCB_TERM_PSC 1/* Page State Change failure */ #define GHCB_TERM_PVALIDATE 2/* Pvalidate failure */ #define GHCB_TERM_NOT_VMPL0 3/* SNP guest is not running at VMPL-0 */ +#define GHCB_TERM_CPUID 4/* CPUID-validation failure */ +#define GHCB_TERM_CPUID_HV 5/* CPUID failure during hypervisor fallback */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/kernel/sev-shared.c +324 -0
369 lines not on this page · raw message
PATCH v12 33/46 x86/boot: Add a pointer to Confidential Computing blob in bootparams
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
The previously defined Confidential Computing blob is provided to the kernel via a setup_data structure or EFI config table entry. Currently these are both checked for by boot/compressed kernel to access the CPUID table address within it for use with SEV-SNP CPUID enforcement.
To also enable SEV-SNP CPUID enforcement for the run-time kernel, similar early access to the CPUID table is needed early on while it's still using the identity-mapped page table set up by boot/compressed, where global pointers need to be accessed via fixup_pointer().
This isn't much of an issue for accessing setup_data, and the EFI config table helper code currently used in boot/compressed *could* be used in this case as well since they both rely on identity-mapping. However, it has some reliance on EFI helpers/string constants that would need to be accessed via fixup_pointer(), and fixing it up while making it shareable between boot/compressed and run-time kernel is fragile and introduces a good bit of uglyness.
Instead, add a boot_params->cc_blob_address pointer that the boot/compressed kernel can initialize so that the run-time kernel can access the CC blob from there instead of re-scanning the EFI config table.
Also document these in Documentation/x86/zero-page.rst. While there, add missing documentation for the acpi_rsdp_addr field, which serves a similar purpose in providing the run-time kernel a pointer to the ACPI RSDP table so that it does not need to [re-]scan the EFI configuration table.
--- Documentation/x86/zero-page.rst | 2 ++ arch/x86/include/asm/bootparam_utils.h | 1 + arch/x86/include/uapi/asm/bootparam.h | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-)
Documentation/x86/zero-page.rst +2 -0
@@ -19,6 +19,7 @@ Offset/Size Proto Name Meaning 058/008 ALL tboot_addr Physical address of tboot shared page 060/010 ALL ist_info Intel SpeedStep (IST) BIOS support information (struct ist_info) +070/008 ALL acpi_rsdp_addr Physical address of ACPI RSDP table 080/010 ALL hd0_info hd0 disk parameter, OBSOLETE!! 090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!! 0A0/010 ALL sys_desc_table System description table (struct sys_desc_table),
@@ -27,6 +28,7 @@ Offset/Size Proto Name Meaning 0C0/004 ALL ext_ramdisk_image ramdisk_image high 32bits 0C4/004 ALL ext_ramdisk_size ramdisk_size high 32bits 0C8/004 ALL ext_cmd_line_ptr cmd_line_ptr high 32bits +13C/004 ALL cc_blob_address Physical address of Confidential Computing blob 140/080 ALL edid_info Video mode setup (struct edid_info) 1C0/020 ALL efi_info EFI 32 information (struct efi_info) 1E0/004 ALL alt_mem_k Alternative mem check, in KB
arch/x86/include/asm/bootparam_utils.h +1 -0
@@ -74,6 +74,7 @@ static void sanitize_boot_params(struct boot_params *boot_params)BOOT_PARAM_PRESERVE (hdr),BOOT_PARAM_PRESERVE (e820_table),BOOT_PARAM_PRESERVE (eddbuf), +BOOT_PARAM_PRESERVE (cc_blob_address), };memset (&scratch,0 ,sizeof (scratch));
arch/x86/include/uapi/asm/bootparam.h +2 -1
@@ -188,7 +188,8 @@ struct boot_params {__u32 ext_ramdisk_image;/* 0x0c0 */ __u32 ext_ramdisk_size;/* 0x0c4 */ __u32 ext_cmd_line_ptr;/* 0x0c8 */ -__u8 _pad4[116 ];/* 0x0cc */ +__u8 _pad4[112 ];/* 0x0cc */ +__u32 cc_blob_address;/* 0x13c */ struct edid_info edid_info;/* 0x140 */ struct efi_info efi_info;/* 0x1c0 */ __u32 alt_mem_k;/* 0x1e0 */
Signature · 1 line
2.25.1
[tip: x86/sev] x86/boot: Add a pointer to Confidential Computing blob in bootparams
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 8c9c509baf660f1062bc758c26008b7f9bbc39f3 Gitweb: https://git.kernel.org/tip/8c9c509baf660f1062bc758c26008b7f9bbc39f3 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:13 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/boot: Add a pointer to Confidential Computing blob in bootparams
The previously defined Confidential Computing blob is provided to the kernel via a setup_data structure or EFI config table entry. Currently, these are both checked for by boot/compressed kernel to access the CPUID table address within it for use with SEV-SNP CPUID enforcement.
To also enable that enforcement for the run-time kernel, similar access to the CPUID table is needed early on while it's still using the identity-mapped page table set up by boot/compressed, where global pointers need to be accessed via fixup_pointer().
This isn't much of an issue for accessing setup_data, and the EFI config table helper code currently used in boot/compressed *could* be used in this case as well since they both rely on identity-mapping. However, it has some reliance on EFI helpers/string constants that would need to be accessed via fixup_pointer(), and fixing it up while making it shareable between boot/compressed and run-time kernel is fragile and introduces a good bit of ugliness.
Instead, add a boot_params->cc_blob_address pointer that the boot/compressed kernel can initialize so that the run-time kernel can access the CC blob from there instead of re-scanning the EFI config table.
Also document these in Documentation/x86/zero-page.rst. While there, add missing documentation for the acpi_rsdp_addr field, which serves a similar purpose in providing the run-time kernel a pointer to the ACPI RSDP table so that it does not need to [re-]scan the EFI configuration table.
[ bp: Fix typos, massage commit message. ]
--- Documentation/x86/zero-page.rst | 2 ++ arch/x86/include/asm/bootparam_utils.h | 1 + arch/x86/include/uapi/asm/bootparam.h | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-)
Documentation/x86/zero-page.rst +2 -0
@@ -19,6 +19,7 @@ Offset/Size Proto Name Meaning 058/008 ALL tboot_addr Physical address of tboot shared page 060/010 ALL ist_info Intel SpeedStep (IST) BIOS support information (struct ist_info) +070/008 ALL acpi_rsdp_addr Physical address of ACPI RSDP table 080/010 ALL hd0_info hd0 disk parameter, OBSOLETE!! 090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!! 0A0/010 ALL sys_desc_table System description table (struct sys_desc_table),
@@ -27,6 +28,7 @@ Offset/Size Proto Name Meaning 0C0/004 ALL ext_ramdisk_image ramdisk_image high 32bits 0C4/004 ALL ext_ramdisk_size ramdisk_size high 32bits 0C8/004 ALL ext_cmd_line_ptr cmd_line_ptr high 32bits +13C/004 ALL cc_blob_address Physical address of Confidential Computing blob 140/080 ALL edid_info Video mode setup (struct edid_info) 1C0/020 ALL efi_info EFI 32 information (struct efi_info) 1E0/004 ALL alt_mem_k Alternative mem check, in KB
arch/x86/include/asm/bootparam_utils.h +1 -0
@@ -74,6 +74,7 @@ static void sanitize_boot_params(struct boot_params *boot_params)BOOT_PARAM_PRESERVE (hdr),BOOT_PARAM_PRESERVE (e820_table),BOOT_PARAM_PRESERVE (eddbuf), +BOOT_PARAM_PRESERVE (cc_blob_address), };memset (&scratch,0 ,sizeof (scratch));
arch/x86/include/uapi/asm/bootparam.h +2 -1
@@ -188,7 +188,8 @@ struct boot_params {__u32 ext_ramdisk_image;/* 0x0c0 */ __u32 ext_ramdisk_size;/* 0x0c4 */ __u32 ext_cmd_line_ptr;/* 0x0c8 */ -__u8 _pad4[116 ];/* 0x0cc */ +__u8 _pad4[112 ];/* 0x0cc */ +__u32 cc_blob_address;/* 0x13c */ struct edid_info edid_info;/* 0x140 */ struct efi_info efi_info;/* 0x1c0 */ __u32 alt_mem_k;/* 0x1e0 */
PATCH v12 34/46 x86/compressed: Add SEV-SNP feature detection/setup
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Initial/preliminary detection of SEV-SNP is done via the Confidential Computing blob. Check for it prior to the normal SEV/SME feature initialization, and add some sanity checks to confirm it agrees with SEV-SNP CPUID/MSR bits.
--- arch/x86/boot/compressed/sev.c | 112 ++++++++++++++++++++++++++++++++- arch/x86/include/asm/sev.h | 3 + 2 files changed, 114 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/sev.c +111 -1
@@ -274,6 +274,13 @@ void sev_enable(struct boot_params *bp) {unsigned int eax, ebx, ecx, edx;struct msr m; +bool snp; + +/* +* Setup/preliminary detection of SNP. This will be sanity-checked +* against CPUID/MSR values later. +*/ + snp =snp_init (bp);/* Check for the SME/SEV support leaf */ eax =0x80000000 ;
@@ -294,8 +301,11 @@ void sev_enable(struct boot_params *bp) ecx =0 ;native_cpuid (&eax, &ebx, &ecx, &edx);/* Check whether SEV is supported */ -if (!(eax &BIT (1 ))) +if (!(eax &BIT (1 ))) { +if (snp) +error ("SEV-SNP support indicated by CC blob, but not CPUID." );return ; + }/* Set the SME mask if this is an SEV guest. */ boot_rdmsr (MSR_AMD64_SEV , &m);
@@ -320,5 +330,105 @@ void sev_enable(struct boot_params *bp)enforce_vmpl0 (); } +if (snp && !(sev_status &MSR_AMD64_SEV_SNP_ENABLED )) +error ("SEV-SNP supported indicated by CC blob, but not SEV status MSR." ); + sme_me_mask =BIT_ULL (ebx &0x3f ); } + +/* Search for Confidential Computing blob in the EFI config table. */ +static struct cc_blob_sev_info *find_cc_blob_efi (struct boot_params *bp) +{ +unsigned long cfg_table_pa; +unsigned int cfg_table_len; +int ret; + + ret =efi_get_conf_table (bp, &cfg_table_pa, &cfg_table_len); +if (ret) +return NULL ; + +return (struct cc_blob_sev_info *)efi_find_vendor_table (bp, cfg_table_pa, + cfg_table_len, +EFI_CC_BLOB_GUID ); +} + +struct cc_setup_data { +struct setup_data header; +u32 cc_blob_address; +}; + +/* +* Search for a Confidential Computing blob passed in as a setup_data entry +* via the Linux Boot Protocol. +*/ +static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) +{ +struct cc_setup_data *sd =NULL ; +struct setup_data *hdr; + + hdr = (struct setup_data *)bp->hdr.setup_data; + +while (hdr) { +if (hdr->type ==SETUP_CC_BLOB ) { + sd = (struct cc_setup_data *)hdr; +return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; + } + hdr = (struct setup_data *)hdr->next; + } + +return NULL ; +} + +/* +* Initial set up of SNP relies on information provided by the +* Confidential Computing blob, which can be passed to the boot kernel +* by firmware/bootloader in the following ways: +* +* - via an entry in the EFI config table +* - via a setup_data structure, as defined by the Linux Boot Protocol +* +* Scan for the blob in that order. +*/ +static struct cc_blob_sev_info *find_cc_blob (struct boot_params *bp) +{ +struct cc_blob_sev_info *cc_info; + + cc_info =find_cc_blob_efi (bp); +if (cc_info) + goto found_cc_info; + + cc_info =find_cc_blob_setup_data (bp); +if (!cc_info) +return NULL ; + +found_cc_info: +if (cc_info->magic !=CC_BLOB_SEV_HDR_MAGIC ) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + +return cc_info; +} + +/* +* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks +* will verify the SNP CPUID/MSR bits. +*/ +bool snp_init (struct boot_params *bp) +{ +struct cc_blob_sev_info *cc_info; + +if (!bp) +return false; + + cc_info =find_cc_blob (bp); +if (!cc_info) +return false; + +/* +* Pass run-time kernel a pointer to CC info via boot_params so EFI +* config table doesn't need to be searched again during early startup +* phase. +*/ + bp->cc_blob_address = (u32 )(unsigned long )cc_info; + +return true; +}
arch/x86/include/asm/sev.h +3 -0
@@ -11,6 +11,7 @@#include <linux/types.h> #include <asm/insn.h> #include <asm/sev-common.h> +#include <asm/bootparam.h> #define GHCB_PROTOCOL_MIN 1ULL#define GHCB_PROTOCOL_MAX 2ULL
@@ -151,6 +152,7 @@ void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op opvoid snp_set_memory_shared (unsigned long vaddr,unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages);void snp_set_wakeup_secondary_cpu (void ); +bool snp_init (struct boot_params *bp);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -168,6 +170,7 @@ static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz,static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_wakeup_secondary_cpu (void ) { } +static inline bool snp_init (struct boot_params *bp) {return false; }#endif #endif
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed: Add SEV-SNP feature detection/setup
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: c01fce9cef8491974f7f007f90281f1608400768 Gitweb: https://git.kernel.org/tip/c01fce9cef8491974f7f007f90281f1608400768 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:14 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/compressed: Add SEV-SNP feature detection/setup
Initial/preliminary detection of SEV-SNP is done via the Confidential Computing blob. Check for it prior to the normal SEV/SME feature initialization, and add some sanity checks to confirm it agrees with SEV-SNP CPUID/MSR bits.
--- arch/x86/boot/compressed/sev.c | 112 +++++++++++++++++++++++++++++++- arch/x86/include/asm/sev.h | 3 +- 2 files changed, 114 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/sev.c +111 -1
@@ -274,6 +274,13 @@ void sev_enable(struct boot_params *bp) {unsigned int eax, ebx, ecx, edx;struct msr m; +bool snp; + +/* +* Setup/preliminary detection of SNP. This will be sanity-checked +* against CPUID/MSR values later. +*/ + snp =snp_init (bp);/* Check for the SME/SEV support leaf */ eax =0x80000000 ;
@@ -294,8 +301,11 @@ void sev_enable(struct boot_params *bp) ecx =0 ;native_cpuid (&eax, &ebx, &ecx, &edx);/* Check whether SEV is supported */ -if (!(eax &BIT (1 ))) +if (!(eax &BIT (1 ))) { +if (snp) +error ("SEV-SNP support indicated by CC blob, but not CPUID." );return ; + }/* Set the SME mask if this is an SEV guest. */ boot_rdmsr (MSR_AMD64_SEV , &m);
@@ -320,5 +330,105 @@ void sev_enable(struct boot_params *bp)enforce_vmpl0 (); } +if (snp && !(sev_status &MSR_AMD64_SEV_SNP_ENABLED )) +error ("SEV-SNP supported indicated by CC blob, but not SEV status MSR." ); + sme_me_mask =BIT_ULL (ebx &0x3f ); } + +/* Search for Confidential Computing blob in the EFI config table. */ +static struct cc_blob_sev_info *find_cc_blob_efi (struct boot_params *bp) +{ +unsigned long cfg_table_pa; +unsigned int cfg_table_len; +int ret; + + ret =efi_get_conf_table (bp, &cfg_table_pa, &cfg_table_len); +if (ret) +return NULL ; + +return (struct cc_blob_sev_info *)efi_find_vendor_table (bp, cfg_table_pa, + cfg_table_len, +EFI_CC_BLOB_GUID ); +} + +struct cc_setup_data { +struct setup_data header; +u32 cc_blob_address; +}; + +/* +* Search for a Confidential Computing blob passed in as a setup_data entry +* via the Linux Boot Protocol. +*/ +static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) +{ +struct cc_setup_data *sd =NULL ; +struct setup_data *hdr; + + hdr = (struct setup_data *)bp->hdr.setup_data; + +while (hdr) { +if (hdr->type ==SETUP_CC_BLOB ) { + sd = (struct cc_setup_data *)hdr; +return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; + } + hdr = (struct setup_data *)hdr->next; + } + +return NULL ; +} + +/* +* Initial set up of SNP relies on information provided by the +* Confidential Computing blob, which can be passed to the boot kernel +* by firmware/bootloader in the following ways: +* +* - via an entry in the EFI config table +* - via a setup_data structure, as defined by the Linux Boot Protocol +* +* Scan for the blob in that order. +*/ +static struct cc_blob_sev_info *find_cc_blob (struct boot_params *bp) +{ +struct cc_blob_sev_info *cc_info; + + cc_info =find_cc_blob_efi (bp); +if (cc_info) + goto found_cc_info; + + cc_info =find_cc_blob_setup_data (bp); +if (!cc_info) +return NULL ; + +found_cc_info: +if (cc_info->magic !=CC_BLOB_SEV_HDR_MAGIC ) +sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); + +return cc_info; +} + +/* +* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks +* will verify the SNP CPUID/MSR bits. +*/ +bool snp_init (struct boot_params *bp) +{ +struct cc_blob_sev_info *cc_info; + +if (!bp) +return false; + + cc_info =find_cc_blob (bp); +if (!cc_info) +return false; + +/* +* Pass run-time kernel a pointer to CC info via boot_params so EFI +* config table doesn't need to be searched again during early startup +* phase. +*/ + bp->cc_blob_address = (u32 )(unsigned long )cc_info; + +return true; +}
arch/x86/include/asm/sev.h +3 -0
@@ -11,6 +11,7 @@#include <linux/types.h> #include <asm/insn.h> #include <asm/sev-common.h> +#include <asm/bootparam.h> #define GHCB_PROTOCOL_MIN 1ULL#define GHCB_PROTOCOL_MAX 2ULL
@@ -151,6 +152,7 @@ void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op opvoid snp_set_memory_shared (unsigned long vaddr,unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages);void snp_set_wakeup_secondary_cpu (void ); +bool snp_init (struct boot_params *bp);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -168,6 +170,7 @@ static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz,static inline void snp_set_memory_shared (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_wakeup_secondary_cpu (void ) { } +static inline bool snp_init (struct boot_params *bp) {return false; }#endif #endif
PATCH v12 35/46 x86/compressed: Use firmware-validated CPUID leaves for SEV-SNP guests
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
SEV-SNP guests will be provided the location of special 'secrets' 'CPUID' pages via the Confidential Computing blob. This blob is provided to the boot kernel either through an EFI config table entry, or via a setup_data structure as defined by the Linux Boot Protocol.
Locate the Confidential Computing from these sources and, if found, use the provided CPUID page/table address to create a copy that the boot kernel will use when servicing cpuid instructions via a #VC CPUID handler.
--- arch/x86/boot/compressed/sev.c | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
arch/x86/boot/compressed/sev.c +46 -0
@@ -408,6 +408,43 @@ static struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)return cc_info; } +/* +* Initialize the kernel's copy of the SNP CPUID table, and set up the +* pointer that will be used to access it. +* +* Maintaining a direct mapping of the SNP CPUID table used by firmware would +* be possible as an alternative, but the approach is brittle since the +* mapping needs to be updated in sync with all the changes to virtual memory +* layout and related mapping facilities throughout the boot process. +*/ +static void setup_cpuid_table (const struct cc_blob_sev_info *cc_info) +{ +const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; +int i; + +if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; +if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table =snp_cpuid_get_table (); +memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); + +/* Initialize CPUID ranges for range-checking. */ +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; + +if (fn->eax_in ==0x0 ) + cpuid_std_range_max = fn->eax; +else if (fn->eax_in ==0x40000000 ) + cpuid_hyp_range_max = fn->eax; +else if (fn->eax_in ==0x80000000 ) + cpuid_ext_range_max = fn->eax; + } +} +/* * Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks * will verify the SNP CPUID/MSR bits.
@@ -423,6 +460,15 @@ bool snp_init(struct boot_params *bp)if (!cc_info)return false; +/* +* If a SNP-specific Confidential Computing blob is present, then +* firmware/bootloader have indicated SNP support. Verifying this +* involves CPUID checks which will be more reliable if the SNP +* CPUID table is used. See comments over snp_setup_cpuid_table() for +* more details. +*/ +setup_cpuid_table (cc_info); +/* * Pass run-time kernel a pointer to CC info via boot_params so EFI * config table doesn't need to be searched again during early startup
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed: Use firmware-validated CPUID leaves for SEV-SNP guests
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 5f211f4fc49622473667e6983bb57beab755f6f6 Gitweb: https://git.kernel.org/tip/5f211f4fc49622473667e6983bb57beab755f6f6 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:15 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/compressed: Use firmware-validated CPUID leaves for SEV-SNP guests
SEV-SNP guests will be provided the location of special 'secrets' 'CPUID' pages via the Confidential Computing blob. This blob is provided to the boot kernel either through an EFI config table entry, or via a setup_data structure as defined by the Linux Boot Protocol.
Locate the Confidential Computing from these sources and, if found, use the provided CPUID page/table address to create a copy that the boot kernel will use when servicing CPUID instructions via a #VC CPUID handler.
[ bp: s/cpuid/CPUID/ ]
--- arch/x86/boot/compressed/sev.c | 46 +++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+)
arch/x86/boot/compressed/sev.c +46 -0
@@ -409,6 +409,43 @@ found_cc_info: }/* +* Initialize the kernel's copy of the SNP CPUID table, and set up the +* pointer that will be used to access it. +* +* Maintaining a direct mapping of the SNP CPUID table used by firmware would +* be possible as an alternative, but the approach is brittle since the +* mapping needs to be updated in sync with all the changes to virtual memory +* layout and related mapping facilities throughout the boot process. +*/ +static void setup_cpuid_table (const struct cc_blob_sev_info *cc_info) +{ +const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; +int i; + +if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; +if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table =snp_cpuid_get_table (); +memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); + +/* Initialize CPUID ranges for range-checking. */ +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; + +if (fn->eax_in ==0x0 ) + cpuid_std_range_max = fn->eax; +else if (fn->eax_in ==0x40000000 ) + cpuid_hyp_range_max = fn->eax; +else if (fn->eax_in ==0x80000000 ) + cpuid_ext_range_max = fn->eax; + } +} + +/* * Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks * will verify the SNP CPUID/MSR bits. */
@@ -424,6 +461,15 @@ bool snp_init(struct boot_params *bp)return false;/* +* If a SNP-specific Confidential Computing blob is present, then +* firmware/bootloader have indicated SNP support. Verifying this +* involves CPUID checks which will be more reliable if the SNP +* CPUID table is used. See comments over snp_setup_cpuid_table() for +* more details. +*/ +setup_cpuid_table (cc_info); + +/* * Pass run-time kernel a pointer to CC info via boot_params so EFI * config table doesn't need to be searched again during early startup * phase.
PATCH v12 36/46 x86/compressed: Export and rename add_identity_map()
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
SEV-specific code will need to add some additional mappings, but doing this within ident_map_64.c requires some SEV-specific helpers to be exported and some SEV-specific struct definitions to be pulled into ident_map_64.c. Instead, export add_identity_map() so SEV-specific (and other subsystem-specific) code can be better contained outside of ident_map_64.c.
While at it, rename the function to kernel_add_identity_map(), similar to the kernel_ident_mapping_init() function it relies upon.
No functional changes.
--- arch/x86/boot/compressed/ident_map_64.c | 18 +++++++++--------- arch/x86/boot/compressed/misc.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-)
arch/x86/boot/compressed/ident_map_64.c +9 -9
@@ -90,7 +90,7 @@ static struct x86_mapping_info mapping_info;/* * Adds the specified range to the identity mappings. */ -static void add_identity_map (unsigned long start,unsigned long end) +void kernel_add_identity_map (unsigned long start,unsigned long end) {int ret;
@@ -157,11 +157,11 @@ void initialize_identity_maps(void *rmode)* explicitly here in case the compressed kernel does not touch them, * or does not touch all the pages covering them. */ -add_identity_map ((unsigned long )_head, (unsigned long )_end); +kernel_add_identity_map ((unsigned long )_head, (unsigned long )_end); boot_params = rmode; -add_identity_map ((unsigned long )boot_params, (unsigned long )(boot_params +1 )); +kernel_add_identity_map ((unsigned long )boot_params, (unsigned long )(boot_params +1 )); cmdline =get_cmd_line_ptr (); -add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE ); +kernel_add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE );/* Load the new page-table. */ sev_verify_cbit (top_level_pgt);
@@ -246,10 +246,10 @@ static int set_clr_page_flags(struct x86_mapping_info *info,* It should already exist, but keep things generic. * * To map the page just read from it and fault it in if there is no -* mapping yet. add_identity_map() can't be called here because that -* would unconditionally map the address on PMD level, destroying any -* PTE-level mappings that might already exist. Use assembly here so -* the access won't be optimized away. +* mapping yet. kernel_add_identity_map() can't be called here because +* that would unconditionally map the address on PMD level, destroying +* any PTE-level mappings that might already exist. Use assembly here +* so the access won't be optimized away. */ asmvolatile ("mov %[address], %%r9" :: [address] "g" (*(unsigned long *)address)
@@ -363,5 +363,5 @@ void do_boot_page_fault(struct pt_regs *regs, unsigned long error_code)* Error code is sane - now identity map the 2M region around * the faulting address. */ -add_identity_map (address, end); +kernel_add_identity_map (address, end); }
arch/x86/boot/compressed/misc.h +1 -0
@@ -156,6 +156,7 @@ static inline int count_immovable_mem_regions(void) { return 0; }#ifdef CONFIG_X86_5LEVEL extern unsigned int __pgtable_l5_enabled, pgdir_shift, ptrs_per_p4d;#endif +extern void kernel_add_identity_map (unsigned long start,unsigned long end);/* Used by PAGE_KERN* macros: */ extern pteval_t __default_kernel_pte_mask;
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed: Export and rename add_identity_map()
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: a9ee679b1f8c3803490ed2eeffb688aaee56583f Gitweb: https://git.kernel.org/tip/a9ee679b1f8c3803490ed2eeffb688aaee56583f Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:16 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/compressed: Export and rename add_identity_map()
SEV-specific code will need to add some additional mappings, but doing this within ident_map_64.c requires some SEV-specific helpers to be exported and some SEV-specific struct definitions to be pulled into ident_map_64.c. Instead, export add_identity_map() so SEV-specific (and other subsystem-specific) code can be better contained outside of ident_map_64.c.
While at it, rename the function to kernel_add_identity_map(), similar to the kernel_ident_mapping_init() function it relies upon.
No functional changes.
--- arch/x86/boot/compressed/ident_map_64.c | 18 +++++++++--------- arch/x86/boot/compressed/misc.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-)
arch/x86/boot/compressed/ident_map_64.c +9 -9
@@ -90,7 +90,7 @@ static struct x86_mapping_info mapping_info;/* * Adds the specified range to the identity mappings. */ -static void add_identity_map (unsigned long start,unsigned long end) +void kernel_add_identity_map (unsigned long start,unsigned long end) {int ret;
@@ -157,11 +157,11 @@ void initialize_identity_maps(void *rmode)* explicitly here in case the compressed kernel does not touch them, * or does not touch all the pages covering them. */ -add_identity_map ((unsigned long )_head, (unsigned long )_end); +kernel_add_identity_map ((unsigned long )_head, (unsigned long )_end); boot_params = rmode; -add_identity_map ((unsigned long )boot_params, (unsigned long )(boot_params +1 )); +kernel_add_identity_map ((unsigned long )boot_params, (unsigned long )(boot_params +1 )); cmdline =get_cmd_line_ptr (); -add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE ); +kernel_add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE );/* Load the new page-table. */ sev_verify_cbit (top_level_pgt);
@@ -246,10 +246,10 @@ static int set_clr_page_flags(struct x86_mapping_info *info,* It should already exist, but keep things generic. * * To map the page just read from it and fault it in if there is no -* mapping yet. add_identity_map() can't be called here because that -* would unconditionally map the address on PMD level, destroying any -* PTE-level mappings that might already exist. Use assembly here so -* the access won't be optimized away. +* mapping yet. kernel_add_identity_map() can't be called here because +* that would unconditionally map the address on PMD level, destroying +* any PTE-level mappings that might already exist. Use assembly here +* so the access won't be optimized away. */ asmvolatile ("mov %[address], %%r9" :: [address] "g" (*(unsigned long *)address)
@@ -363,5 +363,5 @@ void do_boot_page_fault(struct pt_regs *regs, unsigned long error_code)* Error code is sane - now identity map the 2M region around * the faulting address. */ -add_identity_map (address, end); +kernel_add_identity_map (address, end); }
arch/x86/boot/compressed/misc.h +1 -0
@@ -156,6 +156,7 @@ static inline int count_immovable_mem_regions(void) { return 0; }#ifdef CONFIG_X86_5LEVEL extern unsigned int __pgtable_l5_enabled, pgdir_shift, ptrs_per_p4d;#endif +extern void kernel_add_identity_map (unsigned long start,unsigned long end);/* Used by PAGE_KERN* macros: */ extern pteval_t __default_kernel_pte_mask;
PATCH v12 37/46 x86/compressed/64: Add identity mapping for Confidential Computing blob
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
The run-time kernel will need to access the Confidential Computing blob very early in boot to access the CPUID table it points to. At that stage of boot it will be relying on the identity-mapped page table set up by boot/compressed kernel, so make sure the blob and the CPUID table it points to are mapped in advance.
--- arch/x86/boot/compressed/ident_map_64.c | 3 ++- arch/x86/boot/compressed/misc.h | 2 ++ arch/x86/boot/compressed/sev.c | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/ident_map_64.c +2 -1
@@ -163,8 +163,9 @@ void initialize_identity_maps(void *rmode) cmdline =get_cmd_line_ptr ();kernel_add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE ); +sev_prep_identity_maps (top_level_pgt); +/* Load the new page-table. */ -sev_verify_cbit (top_level_pgt);write_cr3 (top_level_pgt); }
arch/x86/boot/compressed/misc.h +2 -0
@@ -127,6 +127,7 @@ void sev_es_shutdown_ghcb(void);extern bool sev_es_check_ghcb_fault (unsigned long address);void snp_set_page_private (unsigned long paddr);void snp_set_page_shared (unsigned long paddr); +void sev_prep_identity_maps (unsigned long top_level_pgt);#else static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }
@@ -136,6 +137,7 @@ static inline bool sev_es_check_ghcb_fault(unsigned long address) }static inline void snp_set_page_private (unsigned long paddr) { }static inline void snp_set_page_shared (unsigned long paddr) { } +static inline void sev_prep_identity_maps (unsigned long top_level_pgt) { }#endif /* acpi.c */
arch/x86/boot/compressed/sev.c +21 -0
@@ -478,3 +478,24 @@ bool snp_init(struct boot_params *bp)return true; } + +void sev_prep_identity_maps (unsigned long top_level_pgt) +{ +/* +* The Confidential Computing blob is used very early in uncompressed +* kernel to find the in-memory cpuid table to handle cpuid +* instructions. Make sure an identity-mapping exists so it can be +* accessed after switchover. +*/ +if (sev_snp_enabled ()) { +unsigned long cc_info_pa = boot_params->cc_blob_address; +struct cc_blob_sev_info *cc_info; + +kernel_add_identity_map (cc_info_pa, cc_info_pa +sizeof (*cc_info)); + + cc_info = (struct cc_blob_sev_info *)cc_info_pa; +kernel_add_identity_map (cc_info->cpuid_phys, cc_info->cpuid_phys + cc_info->cpuid_len); + } + +sev_verify_cbit (top_level_pgt); +}
Signature · 1 line
2.25.1
[tip: x86/sev] x86/compressed/64: Add identity mapping for Confidential Computing blob
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 76f61e1e89b32f3e5d639f1b57413a919066da06 Gitweb: https://git.kernel.org/tip/76f61e1e89b32f3e5d639f1b57413a919066da06 Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:17 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/compressed/64: Add identity mapping for Confidential Computing blob
The run-time kernel will need to access the Confidential Computing blob very early during boot to access the CPUID table it points to. At that stage, it will be relying on the identity-mapped page table set up by the boot/compressed kernel, so make sure the blob and the CPUID table it points to are mapped in advance.
[ bp: Massage. ]
--- arch/x86/boot/compressed/ident_map_64.c | 3 ++- arch/x86/boot/compressed/misc.h | 2 ++ arch/x86/boot/compressed/sev.c | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/ident_map_64.c +2 -1
@@ -163,8 +163,9 @@ void initialize_identity_maps(void *rmode) cmdline =get_cmd_line_ptr ();kernel_add_identity_map (cmdline, cmdline +COMMAND_LINE_SIZE ); +sev_prep_identity_maps (top_level_pgt); +/* Load the new page-table. */ -sev_verify_cbit (top_level_pgt);write_cr3 (top_level_pgt); }
arch/x86/boot/compressed/misc.h +2 -0
@@ -127,6 +127,7 @@ void sev_es_shutdown_ghcb(void);extern bool sev_es_check_ghcb_fault (unsigned long address);void snp_set_page_private (unsigned long paddr);void snp_set_page_shared (unsigned long paddr); +void sev_prep_identity_maps (unsigned long top_level_pgt);#else static inline void sev_enable (struct boot_params *bp) { }static inline void sev_es_shutdown_ghcb (void ) { }
@@ -136,6 +137,7 @@ static inline bool sev_es_check_ghcb_fault(unsigned long address) }static inline void snp_set_page_private (unsigned long paddr) { }static inline void snp_set_page_shared (unsigned long paddr) { } +static inline void sev_prep_identity_maps (unsigned long top_level_pgt) { }#endif /* acpi.c */
arch/x86/boot/compressed/sev.c +21 -0
@@ -478,3 +478,24 @@ bool snp_init(struct boot_params *bp)return true; } + +void sev_prep_identity_maps (unsigned long top_level_pgt) +{ +/* +* The Confidential Computing blob is used very early in uncompressed +* kernel to find the in-memory CPUID table to handle CPUID +* instructions. Make sure an identity-mapping exists so it can be +* accessed after switchover. +*/ +if (sev_snp_enabled ()) { +unsigned long cc_info_pa = boot_params->cc_blob_address; +struct cc_blob_sev_info *cc_info; + +kernel_add_identity_map (cc_info_pa, cc_info_pa +sizeof (*cc_info)); + + cc_info = (struct cc_blob_sev_info *)cc_info_pa; +kernel_add_identity_map (cc_info->cpuid_phys, cc_info->cpuid_phys + cc_info->cpuid_len); + } + +sev_verify_cbit (top_level_pgt); +}
PATCH v12 38/46 x86/sev: Add SEV-SNP feature detection/setup
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
Initial/preliminary detection of SEV-SNP is done via the Confidential Computing blob. Check for it prior to the normal SEV/SME feature initialization, and add some sanity checks to confirm it agrees with SEV-SNP CPUID/MSR bits.
--- arch/x86/boot/compressed/sev.c | 27 ------------- arch/x86/include/asm/sev.h | 2 + arch/x86/kernel/sev-shared.c | 27 +++++++++++++ arch/x86/kernel/sev.c | 64 ++++++++++++++++++++++++++++++ arch/x86/mm/mem_encrypt_identity.c | 8 ++++ 5 files changed, 101 insertions(+), 27 deletions(-)
arch/x86/boot/compressed/sev.c +0 -27
@@ -352,33 +352,6 @@ static struct cc_blob_sev_info *find_cc_blob_efi(struct boot_params *bp) EFI_CC_BLOB_GUID); } -struct cc_setup_data { -struct setup_data header; -u32 cc_blob_address; -}; - -/* -* Search for a Confidential Computing blob passed in as a setup_data entry -* via the Linux Boot Protocol. -*/ -static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) -{ -struct cc_setup_data *sd =NULL ; -struct setup_data *hdr; - - hdr = (struct setup_data *)bp->hdr.setup_data; - -while (hdr) { -if (hdr->type ==SETUP_CC_BLOB ) { - sd = (struct cc_setup_data *)hdr; -return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; - } - hdr = (struct setup_data *)hdr->next; - } - -return NULL ; -} -/* * Initial set up of SNP relies on information provided by the * Confidential Computing blob, which can be passed to the boot kernel
arch/x86/include/asm/sev.h +2 -0
@@ -153,6 +153,7 @@ void snp_set_memory_shared(unsigned long vaddr, unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages);void snp_set_wakeup_secondary_cpu (void );bool snp_init (struct boot_params *bp); +void snp_abort (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -171,6 +172,7 @@ static inline void snp_set_memory_shared(unsigned long vaddr, unsigned int npagestatic inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_wakeup_secondary_cpu (void ) { }static inline bool snp_init (struct boot_params *bp) {return false; } +static inline void snp_abort (void ) { }#endif #endif
arch/x86/kernel/sev-shared.c +27 -0
@@ -937,3 +937,30 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,return ES_OK ; } + +struct cc_setup_data { +struct setup_data header; +u32 cc_blob_address; +}; + +/* +* Search for a Confidential Computing blob passed in as a setup_data entry +* via the Linux Boot Protocol. +*/ +static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) +{ +struct cc_setup_data *sd =NULL ; +struct setup_data *hdr; + + hdr = (struct setup_data *)bp->hdr.setup_data; + +while (hdr) { +if (hdr->type ==SETUP_CC_BLOB ) { + sd = (struct cc_setup_data *)hdr; +return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; + } + hdr = (struct setup_data *)hdr->next; + } + +return NULL ; +}
arch/x86/kernel/sev.c +64 -0
67 lines not on this page · raw message
arch/x86/mm/mem_encrypt_identity.c +8 -0
@@ -45,6 +45,7 @@#include <asm/sections.h> #include <asm/cmdline.h> #include <asm/coco.h> +#include <asm/sev.h> #include "mm_internal.h"
@@ -509,8 +510,11 @@ void __init sme_enable(struct boot_params *bp)bool active_by_default;unsigned long me_mask;char buffer[16 ]; +bool snp;u64 msr; + snp =snp_init (bp); +/* Check for the SME/SEV support leaf */ eax =0x80000000 ; ecx =0 ;
@@ -542,6 +546,10 @@ void __init sme_enable(struct boot_params *bp) sev_status =__rdmsr (MSR_AMD64_SEV ); feature_mask = (sev_status &MSR_AMD64_SEV_ENABLED ) ?AMD_SEV_BIT :AMD_SME_BIT ; +/* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */ +if (snp && !(sev_status &MSR_AMD64_SEV_SNP_ENABLED )) +snp_abort (); +/* Check if memory encryption is enabled */ if (feature_mask ==AMD_SME_BIT ) {/*
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Add SEV-SNP feature detection/setup
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: b190a043c49af4587f5e157053f909192820522a Gitweb: https://git.kernel.org/tip/b190a043c49af4587f5e157053f909192820522a Author: Michael Roth <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:18 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:11 +02:00
x86/sev: Add SEV-SNP feature detection/setup
Initial/preliminary detection of SEV-SNP is done via the Confidential Computing blob. Check for it prior to the normal SEV/SME feature initialization, and add some sanity checks to confirm it agrees with SEV-SNP CPUID/MSR bits.
--- arch/x86/boot/compressed/sev.c | 27 +------------ arch/x86/include/asm/sev.h | 2 +- arch/x86/kernel/sev-shared.c | 27 ++++++++++++- arch/x86/kernel/sev.c | 64 +++++++++++++++++++++++++++++- arch/x86/mm/mem_encrypt_identity.c | 8 ++++- 5 files changed, 101 insertions(+), 27 deletions(-)
arch/x86/boot/compressed/sev.c +0 -27
@@ -352,33 +352,6 @@ static struct cc_blob_sev_info *find_cc_blob_efi(struct boot_params *bp) EFI_CC_BLOB_GUID); } -struct cc_setup_data { -struct setup_data header; -u32 cc_blob_address; -}; - -/* -* Search for a Confidential Computing blob passed in as a setup_data entry -* via the Linux Boot Protocol. -*/ -static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) -{ -struct cc_setup_data *sd =NULL ; -struct setup_data *hdr; - - hdr = (struct setup_data *)bp->hdr.setup_data; - -while (hdr) { -if (hdr->type ==SETUP_CC_BLOB ) { - sd = (struct cc_setup_data *)hdr; -return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; - } - hdr = (struct setup_data *)hdr->next; - } - -return NULL ; -} -/* * Initial set up of SNP relies on information provided by the * Confidential Computing blob, which can be passed to the boot kernel
arch/x86/include/asm/sev.h +2 -0
@@ -153,6 +153,7 @@ void snp_set_memory_shared(unsigned long vaddr, unsigned int npages);void snp_set_memory_private (unsigned long vaddr,unsigned int npages);void snp_set_wakeup_secondary_cpu (void );bool snp_init (struct boot_params *bp); +void snp_abort (void );#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -171,6 +172,7 @@ static inline void snp_set_memory_shared(unsigned long vaddr, unsigned int npagestatic inline void snp_set_memory_private (unsigned long vaddr,unsigned int npages) { }static inline void snp_set_wakeup_secondary_cpu (void ) { }static inline bool snp_init (struct boot_params *bp) {return false; } +static inline void snp_abort (void ) { }#endif #endif
arch/x86/kernel/sev-shared.c +27 -0
@@ -937,3 +937,30 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,return ES_OK ; } + +struct cc_setup_data { +struct setup_data header; +u32 cc_blob_address; +}; + +/* +* Search for a Confidential Computing blob passed in as a setup_data entry +* via the Linux Boot Protocol. +*/ +static struct cc_blob_sev_info *find_cc_blob_setup_data (struct boot_params *bp) +{ +struct cc_setup_data *sd =NULL ; +struct setup_data *hdr; + + hdr = (struct setup_data *)bp->hdr.setup_data; + +while (hdr) { +if (hdr->type ==SETUP_CC_BLOB ) { + sd = (struct cc_setup_data *)hdr; +return (struct cc_blob_sev_info *)(unsigned long )sd->cc_blob_address; + } + hdr = (struct setup_data *)hdr->next; + } + +return NULL ; +}
arch/x86/kernel/sev.c +64 -0
67 lines not on this page · raw message
arch/x86/mm/mem_encrypt_identity.c +8 -0
@@ -45,6 +45,7 @@#include <asm/sections.h> #include <asm/cmdline.h> #include <asm/coco.h> +#include <asm/sev.h> #include "mm_internal.h"
@@ -509,8 +510,11 @@ void __init sme_enable(struct boot_params *bp)bool active_by_default;unsigned long me_mask;char buffer[16 ]; +bool snp;u64 msr; + snp =snp_init (bp); +/* Check for the SME/SEV support leaf */ eax =0x80000000 ; ecx =0 ;
@@ -542,6 +546,10 @@ void __init sme_enable(struct boot_params *bp) sev_status =__rdmsr (MSR_AMD64_SEV ); feature_mask = (sev_status &MSR_AMD64_SEV_ENABLED ) ?AMD_SEV_BIT :AMD_SME_BIT ; +/* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */ +if (snp && !(sev_status &MSR_AMD64_SEV_SNP_ENABLED )) +snp_abort (); +/* Check if memory encryption is enabled */ if (feature_mask ==AMD_SME_BIT ) {/*
PATCH v12 39/46 x86/sev: Use firmware-validated CPUID for SEV-SNP guests
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
SEV-SNP guests will be provided the location of special 'secrets' and 'CPUID' pages via the Confidential Computing blob. This blob is provided to the run-time kernel either through a bootparams field that was initialized by the boot/compressed kernel, or via a setup_data structure as defined by the Linux Boot Protocol.
Locate the Confidential Computing blob from these sources and, if found, use the provided CPUID page/table address to create a copy that the run-time kernel will use when servicing CPUID instructions via a #VC handler.
--- arch/x86/boot/compressed/sev.c | 37 ---------------------------------- arch/x86/kernel/sev-shared.c | 37 ++++++++++++++++++++++++++++++++++ arch/x86/kernel/sev.c | 24 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 37 deletions(-)
arch/x86/boot/compressed/sev.c +0 -37
@@ -381,43 +381,6 @@ static struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)return cc_info; } -/* -* Initialize the kernel's copy of the SNP CPUID table, and set up the -* pointer that will be used to access it. -* -* Maintaining a direct mapping of the SNP CPUID table used by firmware would -* be possible as an alternative, but the approach is brittle since the -* mapping needs to be updated in sync with all the changes to virtual memory -* layout and related mapping facilities throughout the boot process. -*/ -static void setup_cpuid_table (const struct cc_blob_sev_info *cc_info) -{ -const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; -int i; - -if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); - - cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; -if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); - - cpuid_table =snp_cpuid_get_table (); -memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); - -/* Initialize CPUID ranges for range-checking. */ -for (i =0 ; i < cpuid_table->count; i++) { -const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; - -if (fn->eax_in ==0x0 ) - cpuid_std_range_max = fn->eax; -else if (fn->eax_in ==0x40000000 ) - cpuid_hyp_range_max = fn->eax; -else if (fn->eax_in ==0x80000000 ) - cpuid_ext_range_max = fn->eax; - } -} -/* * Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks * will verify the SNP CPUID/MSR bits.
arch/x86/kernel/sev-shared.c +37 -0
@@ -964,3 +964,40 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)return NULL ; } + +/* +* Initialize the kernel's copy of the SNP CPUID table, and set up the +* pointer that will be used to access it. +* +* Maintaining a direct mapping of the SNP CPUID table used by firmware would +* be possible as an alternative, but the approach is brittle since the +* mapping needs to be updated in sync with all the changes to virtual memory +* layout and related mapping facilities throughout the boot process. +*/ +static void __init setup_cpuid_table (const struct cc_blob_sev_info *cc_info) +{ +const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; +int i; + +if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; +if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table =snp_cpuid_get_table (); +memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); + +/* Initialize CPUID ranges for range-checking. */ +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; + +if (fn->eax_in ==0x0 ) + cpuid_std_range_max = fn->eax; +else if (fn->eax_in ==0x40000000 ) + cpuid_hyp_range_max = fn->eax; +else if (fn->eax_in ==0x80000000 ) + cpuid_ext_range_max = fn->eax; + } +}
arch/x86/kernel/sev.c +24 -0
@@ -34,6 +34,7 @@#include <asm/cpu.h> #include <asm/apic.h> #include <asm/cpuid.h> +#include <asm/cmdline.h> #define DR7_RESET_VALUE 0x400
@@ -2028,6 +2029,8 @@ bool __init snp_init(struct boot_params *bp)if (!cc_info)return false; +setup_cpuid_table (cc_info); +/* * The CC blob will be used later to access the secrets page. Cache * it here like the boot kernel does.
@@ -2041,3 +2044,24 @@ void __init snp_abort(void) {sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); } + +/* +* It is useful from an auditing/testing perspective to provide an easy way +* for the guest owner to know that the CPUID table has been initialized as +* expected, but that initialization happens too early in boot to print any +* sort of indicator, and there's not really any other good place to do it, +* so do it here. +*/ +static int __init report_cpuid_table (void ) +{ +const struct snp_cpuid_table *cpuid_table =snp_cpuid_get_table (); + +if (!cpuid_table->count) +return 0 ; + +pr_info ("Using SNP CPUID table, %d entries present.\n" , + cpuid_table->count); + +return 0 ; +} +arch_initcall (report_cpuid_table);
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Use firmware-validated CPUID for SEV-SNP guests
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 30612045e69d088f1effd748048ebb0e282984ec Gitweb: https://git.kernel.org/tip/30612045e69d088f1effd748048ebb0e282984ec Author: Michael Roth <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:49 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:12 +02:00
x86/sev: Use firmware-validated CPUID for SEV-SNP guests
SEV-SNP guests will be provided the location of special 'secrets' and 'CPUID' pages via the Confidential Computing blob. This blob is provided to the run-time kernel either through a boot_params field that was initialized by the boot/compressed kernel, or via a setup_data structure as defined by the Linux Boot Protocol.
Locate the Confidential Computing blob from these sources and, if found, use the provided CPUID page/table address to create a copy that the run-time kernel will use when servicing CPUID instructions via a #VC handler.
--- arch/x86/boot/compressed/sev.c | 37 +--------------------------------- arch/x86/kernel/sev-shared.c | 37 +++++++++++++++++++++++++++++++++- arch/x86/kernel/sev.c | 24 +++++++++++++++++++++- 3 files changed, 61 insertions(+), 37 deletions(-)
arch/x86/boot/compressed/sev.c +0 -37
@@ -382,43 +382,6 @@ found_cc_info: }/* -* Initialize the kernel's copy of the SNP CPUID table, and set up the -* pointer that will be used to access it. -* -* Maintaining a direct mapping of the SNP CPUID table used by firmware would -* be possible as an alternative, but the approach is brittle since the -* mapping needs to be updated in sync with all the changes to virtual memory -* layout and related mapping facilities throughout the boot process. -*/ -static void setup_cpuid_table (const struct cc_blob_sev_info *cc_info) -{ -const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; -int i; - -if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); - - cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; -if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); - - cpuid_table =snp_cpuid_get_table (); -memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); - -/* Initialize CPUID ranges for range-checking. */ -for (i =0 ; i < cpuid_table->count; i++) { -const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; - -if (fn->eax_in ==0x0 ) - cpuid_std_range_max = fn->eax; -else if (fn->eax_in ==0x40000000 ) - cpuid_hyp_range_max = fn->eax; -else if (fn->eax_in ==0x80000000 ) - cpuid_ext_range_max = fn->eax; - } -} - -/* * Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks * will verify the SNP CPUID/MSR bits. */
arch/x86/kernel/sev-shared.c +37 -0
@@ -964,3 +964,40 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)return NULL ; } + +/* +* Initialize the kernel's copy of the SNP CPUID table, and set up the +* pointer that will be used to access it. +* +* Maintaining a direct mapping of the SNP CPUID table used by firmware would +* be possible as an alternative, but the approach is brittle since the +* mapping needs to be updated in sync with all the changes to virtual memory +* layout and related mapping facilities throughout the boot process. +*/ +static void __init setup_cpuid_table (const struct cc_blob_sev_info *cc_info) +{ +const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; +int i; + +if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len <PAGE_SIZE ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys; +if (!cpuid_table_fw->count || cpuid_table_fw->count >SNP_CPUID_COUNT_MAX ) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_CPUID ); + + cpuid_table =snp_cpuid_get_table (); +memcpy ((void *)cpuid_table, cpuid_table_fw,sizeof (*cpuid_table)); + +/* Initialize CPUID ranges for range-checking. */ +for (i =0 ; i < cpuid_table->count; i++) { +const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; + +if (fn->eax_in ==0x0 ) + cpuid_std_range_max = fn->eax; +else if (fn->eax_in ==0x40000000 ) + cpuid_hyp_range_max = fn->eax; +else if (fn->eax_in ==0x80000000 ) + cpuid_ext_range_max = fn->eax; + } +}
arch/x86/kernel/sev.c +24 -0
@@ -34,6 +34,7 @@#include <asm/cpu.h> #include <asm/apic.h> #include <asm/cpuid.h> +#include <asm/cmdline.h> #define DR7_RESET_VALUE 0x400
@@ -2025,6 +2026,8 @@ bool __init snp_init(struct boot_params *bp)if (!cc_info)return false; +setup_cpuid_table (cc_info); +/* * The CC blob will be used later to access the secrets page. Cache * it here like the boot kernel does.
@@ -2038,3 +2041,24 @@ void __init snp_abort(void) {sev_es_terminate (SEV_TERM_SET_GEN ,GHCB_SNP_UNSUPPORTED ); } + +/* +* It is useful from an auditing/testing perspective to provide an easy way +* for the guest owner to know that the CPUID table has been initialized as +* expected, but that initialization happens too early in boot to print any +* sort of indicator, and there's not really any other good place to do it, +* so do it here. +*/ +static int __init report_cpuid_table (void ) +{ +const struct snp_cpuid_table *cpuid_table =snp_cpuid_get_table (); + +if (!cpuid_table->count) +return 0 ; + +pr_info ("Using SNP CPUID table, %d entries present.\n" , + cpuid_table->count); + +return 0 ; +} +arch_initcall (report_cpuid_table);
PATCH v12 40/46 x86/sev: add sev=debug cmdline option to dump SNP CPUID table
In reply to Brijesh SinghFrom: Michael Roth <[email protected]>
For debugging purposes it is very useful to have a way to see the full contents of the SNP CPUID table provided to a guest. Add an sev=debug kernel command-line option to do so.
Also introduce some infrastructure so that additional options can be specified via sev=option1[,option2] over time in a consistent manner.
--- .../admin-guide/kernel-parameters.txt | 2 + Documentation/x86/x86_64/boot-options.rst | 14 +++++ arch/x86/kernel/sev.c | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +2 -0
@@ -5229,6 +5229,8 @@ serialnumber [BUGS=X86-32] + sev=option[,option...] [X86-64] See Documentation/x86/x86_64/boot-options.rst + shapers= [NET] Maximal number of shapers.
Documentation/x86/x86_64/boot-options.rst +14 -0
@@ -310,3 +310,17 @@ Miscellaneous Do not use GB pages for kernel direct mappings. gbpages Use GB pages for kernel direct mappings. + + +AMD SEV (Secure Encrypted Virtualization) +========================================= +Options relating to AMD SEV, specified via the following format: + +:: + + sev=option1[,option2] + +The available options are: + + debug + Enable verbose debug messages.
arch/x86/kernel/sev.c +58 -0
76 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v12 40/46] x86/sev: add sev=debug cmdline option to dump SNP CPUID table
Quoted 9 lines · Brijesh Singh
From: Michael Roth <[email protected]>
For debugging purposes it is very useful to have a way to see the full contents of the SNP CPUID table provided to a guest. Add an sev=debug kernel command-line option to do so.
Also introduce some infrastructure so that additional options can be specified via sev=option1[,option2] over time in a consistent manner.
Quoted 7 lines
Suggested-by Borislav Petkov <[email protected]>Signed-off-by Michael Roth <[email protected]>--- .../admin-guide/kernel-parameters.txt | 2 + Documentation/x86/x86_64/boot-options.rst | 14 +++++ arch/x86/kernel/sev.c | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+)
I simplified the string parsing:
---
From: Michael Roth <[email protected]>
Date: Mon, 7 Mar 2022 15:33:50 -0600
Subject: [PATCH] x86/sev: Add a sev= cmdline option
For debugging purposes it is very useful to have a way to see the full contents of the SNP CPUID table provided to a guest. Add an sev=debug kernel command-line option to do so.
Also introduce some infrastructure so that additional options can be specified via sev=option1[,option2] over time in a consistent manner.
[ bp: Massage, simplify string parsing. ]
--- .../admin-guide/kernel-parameters.txt | 2 + Documentation/x86/x86_64/boot-options.rst | 14 ++++++ arch/x86/kernel/sev.c | 44 +++++++++++++++++++ 3 files changed, 60 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +2 -0
@@ -5229,6 +5229,8 @@ serialnumber [BUGS=X86-32] + sev=option[,option...] [X86-64] See Documentation/x86/x86_64/boot-options.rst + shapers= [NET] Maximal number of shapers.
Documentation/x86/x86_64/boot-options.rst +14 -0
@@ -317,3 +317,17 @@ Miscellaneous Do not use GB pages for kernel direct mappings. gbpages Use GB pages for kernel direct mappings. + + +AMD SEV (Secure Encrypted Virtualization) +========================================= +Options relating to AMD SEV, specified via the following format: + +:: + + sev=option1[,option2] + +The available options are: + + debug + Enable debug messages.
arch/x86/kernel/sev.c +44 -0
62 lines not on this page · raw message
Signature · 7 lines
2.35.1
--
Regards/Gruss,
Boris.
SUSE Software Solutions Germany GmbH, GF: Ivo Totev, HRB 36809, AG Nürnberg[tip: x86/sev] x86/sev: Add a sev= cmdline option
In reply to Brijesh SinghThe following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: ba37a1438aeb540cc48722d629f4b2e7e4398466 Gitweb: https://git.kernel.org/tip/ba37a1438aeb540cc48722d629f4b2e7e4398466 Author: Michael Roth <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:50 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:12 +02:00
x86/sev: Add a sev= cmdline option
For debugging purposes it is very useful to have a way to see the full contents of the SNP CPUID table provided to a guest. Add an sev=debug kernel command-line option to do so.
Also introduce some infrastructure so that additional options can be specified via sev=option1[,option2] over time in a consistent manner.
[ bp: Massage, simplify string parsing. ]
--- Documentation/admin-guide/kernel-parameters.txt | 2 +- Documentation/x86/x86_64/boot-options.rst | 14 +++++- arch/x86/kernel/sev.c | 44 ++++++++++++++++- 3 files changed, 60 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +2 -0
@@ -5308,6 +5308,8 @@ serialnumber [BUGS=X86-32] + sev=option[,option...] [X86-64] See Documentation/x86/x86_64/boot-options.rst + shapers= [NET] Maximal number of shapers.
Documentation/x86/x86_64/boot-options.rst +14 -0
@@ -310,3 +310,17 @@ Miscellaneous Do not use GB pages for kernel direct mappings. gbpages Use GB pages for kernel direct mappings. + + +AMD SEV (Secure Encrypted Virtualization) +========================================= +Options relating to AMD SEV, specified via the following format: + +:: + + sev=option1[,option2] + +The available options are: + + debug + Enable debug messages.
arch/x86/kernel/sev.c +44 -0
62 lines not on this page · raw message
PATCH v12 41/46 x86/sev: Provide support for SNP guest request NAEs
In reply to Brijesh SinghVersion 2 of GHCB specification provides SNP_GUEST_REQUEST and SNP_EXT_GUEST_REQUEST NAE that can be used by the SNP guest to communicate with the PSP.
While at it, add a snp_issue_guest_request() helper that will be used by driver or other subsystem to issue the request to PSP.
See SEV-SNP firmware and GHCB spec for more details.
--- arch/x86/include/asm/sev-common.h | 3 ++ arch/x86/include/asm/sev.h | 14 ++++++++ arch/x86/include/uapi/asm/svm.h | 4 +++ arch/x86/kernel/sev.c | 57 +++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+)
arch/x86/include/asm/sev-common.h +3 -0
@@ -128,6 +128,9 @@ struct snp_psc_desc {struct psc_entry entries[VMGEXIT_PSC_MAX_ENTRY ]; } __packed; +/* Guest message request error code */ +#define SNP_GUEST_REQ_INVALID_LEN BIT_ULL(32) +#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12#define GHCB_MSR_TERM_REASON_SET_MASK 0xf
arch/x86/include/asm/sev.h +14 -0
@@ -87,6 +87,14 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);#define RMPADJUST_VMSA_PAGE_BIT BIT(16) +/* SNP Guest message request */ +struct snp_req_data { +unsigned long req_gpa; +unsigned long resp_gpa; +unsigned long data_gpa; +unsigned int data_npages; +}; +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -154,6 +162,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned int npages);void snp_set_wakeup_secondary_cpu (void );bool snp_init (struct boot_params *bp);void snp_abort (void ); +int snp_issue_guest_request (u64 exit_code,struct snp_req_data *input,unsigned long *fw_err);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -173,6 +182,11 @@ static inline void snp_set_memory_private(unsigned long vaddr, unsigned int npagstatic inline void snp_set_wakeup_secondary_cpu (void ) { }static inline bool snp_init (struct boot_params *bp) {return false; }static inline void snp_abort (void ) { } +static inline int snp_issue_guest_request (u64 exit_code,struct snp_req_data *input, +unsigned long *fw_err) +{ +return -ENOTTY ; +}#endif #endif
arch/x86/include/uapi/asm/svm.h +4 -0
@@ -109,6 +109,8 @@#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1#define SVM_VMGEXIT_PSC 0x80000010 +#define SVM_VMGEXIT_GUEST_REQUEST 0x80000011 +#define SVM_VMGEXIT_EXT_GUEST_REQUEST 0x80000012#define SVM_VMGEXIT_AP_CREATION 0x80000013#define SVM_VMGEXIT_AP_CREATE_ON_INIT 0#define SVM_VMGEXIT_AP_CREATE 1
@@ -225,6 +227,8 @@ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ + { SVM_VMGEXIT_GUEST_REQUEST, "vmgexit_guest_request" }, \ + { SVM_VMGEXIT_EXT_GUEST_REQUEST, "vmgexit_ext_guest_request" }, \ { SVM_VMGEXIT_AP_CREATION, "vmgexit_ap_creation" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +57 -0
60 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Provide support for SNP guest request NAEs
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: d5af44dde5461d125d1602ac913ab5c6bdf09b8b Gitweb: https://git.kernel.org/tip/d5af44dde5461d125d1602ac913ab5c6bdf09b8b Author: Brijesh Singh <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:51 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:12 +02:00
x86/sev: Provide support for SNP guest request NAEs
Version 2 of GHCB specification provides SNP_GUEST_REQUEST and SNP_EXT_GUEST_REQUEST NAE that can be used by the SNP guest to communicate with the PSP.
While at it, add a snp_issue_guest_request() helper that will be used by driver or other subsystem to issue the request to PSP.
See SEV-SNP firmware and GHCB spec for more details.
--- arch/x86/include/asm/sev-common.h | 3 ++- arch/x86/include/asm/sev.h | 14 +++++++- arch/x86/include/uapi/asm/svm.h | 4 ++- arch/x86/kernel/sev.c | 57 ++++++++++++++++++++++++++++++- 4 files changed, 78 insertions(+)
arch/x86/include/asm/sev-common.h +3 -0
@@ -128,6 +128,9 @@ struct snp_psc_desc {struct psc_entry entries[VMGEXIT_PSC_MAX_ENTRY ]; } __packed; +/* Guest message request error code */ +#define SNP_GUEST_REQ_INVALID_LEN BIT_ULL(32) +#define GHCB_MSR_TERM_REQ 0x100#define GHCB_MSR_TERM_REASON_SET_POS 12#define GHCB_MSR_TERM_REASON_SET_MASK 0xf
arch/x86/include/asm/sev.h +14 -0
@@ -87,6 +87,14 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);#define RMPADJUST_VMSA_PAGE_BIT BIT(16) +/* SNP Guest message request */ +struct snp_req_data { +unsigned long req_gpa; +unsigned long resp_gpa; +unsigned long data_gpa; +unsigned int data_npages; +}; +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
@@ -154,6 +162,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned int npages);void snp_set_wakeup_secondary_cpu (void );bool snp_init (struct boot_params *bp);void snp_abort (void ); +int snp_issue_guest_request (u64 exit_code,struct snp_req_data *input,unsigned long *fw_err);#else static inline void sev_es_ist_enter (struct pt_regs *regs) { }static inline void sev_es_ist_exit (void ) { }
@@ -173,6 +182,11 @@ static inline void snp_set_memory_private(unsigned long vaddr, unsigned int npagstatic inline void snp_set_wakeup_secondary_cpu (void ) { }static inline bool snp_init (struct boot_params *bp) {return false; }static inline void snp_abort (void ) { } +static inline int snp_issue_guest_request (u64 exit_code,struct snp_req_data *input, +unsigned long *fw_err) +{ +return -ENOTTY ; +}#endif #endif
arch/x86/include/uapi/asm/svm.h +4 -0
@@ -109,6 +109,8 @@#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1#define SVM_VMGEXIT_PSC 0x80000010 +#define SVM_VMGEXIT_GUEST_REQUEST 0x80000011 +#define SVM_VMGEXIT_EXT_GUEST_REQUEST 0x80000012#define SVM_VMGEXIT_AP_CREATION 0x80000013#define SVM_VMGEXIT_AP_CREATE_ON_INIT 0#define SVM_VMGEXIT_AP_CREATE 1
@@ -225,6 +227,8 @@ { SVM_VMGEXIT_AP_HLT_LOOP, "vmgexit_ap_hlt_loop" }, \ { SVM_VMGEXIT_AP_JUMP_TABLE, "vmgexit_ap_jump_table" }, \ { SVM_VMGEXIT_PSC, "vmgexit_page_state_change" }, \ + { SVM_VMGEXIT_GUEST_REQUEST, "vmgexit_guest_request" }, \ + { SVM_VMGEXIT_EXT_GUEST_REQUEST, "vmgexit_ext_guest_request" }, \ { SVM_VMGEXIT_AP_CREATION, "vmgexit_ap_creation" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ { SVM_EXIT_ERR, "invalid_guest_state" }
arch/x86/kernel/sev.c +57 -0
60 lines not on this page · raw message
PATCH v12 42/46 x86/sev: Register SEV-SNP guest request platform device
In reply to Brijesh SinghVersion 2 of the GHCB specification providesa Non Automatic Exit (NAE) event type that can be used by the SEV-SNP guest to communicate with the PSP without risk from a malicious hypervisor who wishes to read, alter, drop or replay the messages sent.
SNP_LAUNCH_UPDATE can insert two special pages into the guest’s memory:
the secrets page and the CPUID page. The PSP firmware populates the contents of the secrets page. The secrets page contains encryption keys used by the guest to interact with the firmware. Because the secrets page is encrypted with the guest’s memory encryption key, the hypervisor cannot read the keys. See SEV-SNP firmware spec for further details on the secrets page format.
Create a platform device that the SEV-SNP guest driver can bind to get the platform resources such as encryption key and message id to use to communicate with the PSP. The SEV-SNP guest driver provides a userspace interface to get the attestation report, key derivation, extended attestation report etc.
--- arch/x86/include/asm/sev.h | 4 +++ arch/x86/kernel/sev.c | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+)
arch/x86/include/asm/sev.h +4 -0
@@ -95,6 +95,10 @@ struct snp_req_data {unsigned int data_npages; }; +struct snp_guest_platform_data { +u64 secrets_gpa; +}; +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
arch/x86/kernel/sev.c +56 -0
65 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] x86/sev: Register SEV-SNP guest request platform device
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: 3a45b3753849c4a12cca2dd176c0192cd2a63e62 Gitweb: https://git.kernel.org/tip/3a45b3753849c4a12cca2dd176c0192cd2a63e62 Author: Brijesh Singh <[email protected]> AuthorDate: Thu, 24 Feb 2022 10:56:21 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:12 +02:00
x86/sev: Register SEV-SNP guest request platform device
Version 2 of the GHCB specification provides a Non Automatic Exit (NAE) event type that can be used by the SEV-SNP guest to communicate with the PSP without risk from a malicious hypervisor who wishes to read, alter, drop or replay the messages sent.
SNP_LAUNCH_UPDATE can insert two special pages into the guest’s memory:
the secrets page and the CPUID page. The PSP firmware populates the contents of the secrets page. The secrets page contains encryption keys used by the guest to interact with the firmware. Because the secrets page is encrypted with the guest’s memory encryption key, the hypervisor cannot read the keys. See SEV-SNP firmware spec for further details on the secrets page format.
Create a platform device that the SEV-SNP guest driver can bind to get the platform resources such as encryption key and message id to use to communicate with the PSP. The SEV-SNP guest driver provides a userspace interface to get the attestation report, key derivation, extended attestation report etc.
--- arch/x86/include/asm/sev.h | 4 +++- arch/x86/kernel/sev.c | 56 +++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+)
arch/x86/include/asm/sev.h +4 -0
@@ -95,6 +95,10 @@ struct snp_req_data {unsigned int data_npages; }; +struct snp_guest_platform_data { +u64 secrets_gpa; +}; +#ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key;extern void __sev_es_ist_enter (struct pt_regs *regs);
arch/x86/kernel/sev.c +56 -0
65 lines not on this page · raw message
PATCH v12 43/46 virt: Add SEV-SNP guest driver
In reply to Brijesh SinghThe SEV-SNP specification provides the guest a mechanism to communicate with the PSP without risk from a malicious hypervisor who wishes to read, alter, drop or replay the messages sent. The driver uses snp_issue_guest_request() to issue GHCB SNP_GUEST_REQUEST or SNP_EXT_GUEST_REQUEST NAE events to submit the request to PSP.
The PSP requires that all communication should be encrypted using key specified through the platform_data.
Userspace can use SNP_GET_REPORT ioctl() to query the guest attestation report.
The {alloc_free}_shared_pages() is used for allocating the shared buffer used by the driver to communicate with the PSP. Later patches will use it to allocate the certificate blob and more.
See SEV-SNP spec section Guest Messages for more details.
--- Documentation/virt/coco/sevguest.rst | 86 ++++ Documentation/virt/index.rst | 1 + drivers/virt/Kconfig | 3 + drivers/virt/Makefile | 1 + drivers/virt/coco/sevguest/Kconfig | 14 + drivers/virt/coco/sevguest/Makefile | 2 + drivers/virt/coco/sevguest/sevguest.c | 607 ++++++++++++++++++++++++++ drivers/virt/coco/sevguest/sevguest.h | 98 +++++ include/uapi/linux/sev-guest.h | 50 +++ 9 files changed, 862 insertions(+) create mode 100644 Documentation/virt/coco/sevguest.rst create mode 100644 drivers/virt/coco/sevguest/Kconfig create mode 100644 drivers/virt/coco/sevguest/Makefile create mode 100644 drivers/virt/coco/sevguest/sevguest.c create mode 100644 drivers/virt/coco/sevguest/sevguest.h create mode 100644 include/uapi/linux/sev-guest.h
Documentation/virt/coco/sevguest.rst new file +86 -0
@@ -0,0 +1,86 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================================================== +The Definitive SEV Guest API Documentation +=================================================================== + +1. General description +====================== + +The SEV API is a set of ioctls that are used by the guest or hypervisor +to get or set a certain aspect of the SEV virtual machine. The ioctls belong +to the following classes: + + - Hypervisor ioctls: These query and set global attributes which affect the + whole SEV firmware. These ioctl are used by platform provisioning tools. + + - Guest ioctls: These query and set attributes of the SEV virtual machine. + +2. API description +================== + +This section describes ioctls that is used for querying the SEV guest report +from the SEV firmware. For each ioctl, the following information is provided +along with a description: + + Technology: + which SEV technology provides this ioctl. SEV, SEV-ES, SEV-SNP or all. + + Type: + hypervisor or guest. The ioctl can be used inside the guest or the + hypervisor. + + Parameters: + what parameters are accepted by the ioctl. + + Returns: + the return value. General error numbers (-ENOMEM, -EINVAL) + are not detailed, but errors with specific meanings are. + +The guest ioctl should be issued on a file descriptor of the /dev/sev-guest device. +The ioctl accepts struct snp_user_guest_request. The input and output structure is +specified through the req_data and resp_data field respectively. If the ioctl fails +to execute due to a firmware error, then fw_err code will be set otherwise the +fw_err will be set to 0x00000000000000ff. + +The firmware checks that the message sequence counter is one greater than +the guests message sequence counter. If guest driver fails to increment message +counter (e.g counter overflow), then -EIO will be returned. + +:: + + struct snp_guest_request_ioctl { + /* Message version number */ + __u32 msg_version; + + /* Request and response structure address */ + __u64 req_data; + __u64 resp_data; + + /* firmware error code on failure (see psp-sev.h) */ + __u64 fw_err; + }; + +2.1 SNP_GET_REPORT +------------------ + +:Technology: sev-snp +:Type: guest ioctl +:Parameters (in): struct snp_report_req +:Returns (out): struct snp_report_resp on success, -negative on error + +The SNP_GET_REPORT ioctl can be used to query the attestation report from the +SEV-SNP firmware. The ioctl uses the SNP_GUEST_REQUEST (MSG_REPORT_REQ) command +provided by the SEV-SNP firmware to query the attestation report. + +On success, the snp_report_resp.data will contains the report. The report +contain the format described in the SEV-SNP specification. See the SEV-SNP +specification for further details. + + +Reference +--------- + +SEV-SNP and GHCB specification: developer.amd.com/sev + +The driver is based on SEV-SNP firmware spec 0.9 and GHCB spec version 2.0.
Documentation/virt/index.rst +1 -0
@@ -13,6 +13,7 @@ Linux Virtualization Support guest-halt-polling ne_overview acrn/index + coco/sevguest .. only:: html and subproject
drivers/virt/Kconfig +3 -0
@@ -36,4 +36,7 @@ source "drivers/virt/vboxguest/Kconfig" source "drivers/virt/nitro_enclaves/Kconfig" source "drivers/virt/acrn/Kconfig" + +source "drivers/virt/coco/sevguest/Kconfig" + endif
drivers/virt/Makefile +1 -0
@@ -8,3 +8,4 @@ obj-y += vboxguest/ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/ obj-$(CONFIG_ACRN_HSM) += acrn/ +obj-$(CONFIG_SEV_GUEST) += coco/sevguest/
drivers/virt/coco/sevguest/Kconfig new file +14 -0
@@ -0,0 +1,14 @@ +config SEV_GUEST + tristate "AMD SEV Guest driver" + default m + depends on AMD_MEM_ENCRYPT + select CRYPTO_AEAD2 + select CRYPTO_GCM + help + SEV-SNP firmware provides the guest a mechanism to communicate with + the PSP without risk from a malicious hypervisor who wishes to read, + alter, drop or replay the messages sent. The driver provides + userspace interface to communicate with the PSP to request the + attestation report and more. + + If you choose 'M' here, this module will be called sevguest.
drivers/virt/coco/sevguest/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_SEV_GUEST) += sevguest.o
drivers/virt/coco/sevguest/sevguest.c new file +607 -0
607 lines not on this page · raw message
drivers/virt/coco/sevguest/sevguest.h new file +98 -0
98 lines not on this page · raw message
include/uapi/linux/sev-guest.h new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
2.25.1
[tip: x86/sev] virt: Add SEV-SNP guest driver
The following commit has been merged into the x86/sev branch of tip:
The following commit has been merged into the x86/sev branch of tip:
Commit-ID: fce96cf0443083e37455eff8f78fd240c621dae3 Gitweb: https://git.kernel.org/tip/fce96cf0443083e37455eff8f78fd240c621dae3 Author: Brijesh Singh <[email protected]> AuthorDate: Mon, 07 Mar 2022 15:33:53 -06:00 Committer: Borislav Petkov <[email protected]> CommitterDate: Thu, 07 Apr 2022 16:47:12 +02:00
virt: Add SEV-SNP guest driver
The SEV-SNP specification provides the guest a mechanism to communicate with the PSP without risk from a malicious hypervisor who wishes to read, alter, drop or replay the messages sent. The driver uses snp_issue_guest_request() to issue GHCB SNP_GUEST_REQUEST or SNP_EXT_GUEST_REQUEST NAE events to submit the request to PSP.
The PSP requires that all communication should be encrypted using key specified through a struct snp_guest_platform_data descriptor.
Userspace can use SNP_GET_REPORT ioctl() to query the guest attestation report.
See SEV-SNP spec section Guest Messages for more details.
[ bp: Remove the "what" from the commit message, massage. ]
--- Documentation/virt/coco/sevguest.rst | 86 ++++- Documentation/virt/index.rst | 1 +- drivers/virt/Kconfig | 3 +- drivers/virt/Makefile | 1 +- drivers/virt/coco/sevguest/Kconfig | 14 +- drivers/virt/coco/sevguest/Makefile | 2 +- drivers/virt/coco/sevguest/sevguest.c | 607 +++++++++++++++++++++++++- drivers/virt/coco/sevguest/sevguest.h | 98 ++++- include/uapi/linux/sev-guest.h | 50 ++- 9 files changed, 862 insertions(+) create mode 100644 Documentation/virt/coco/sevguest.rst create mode 100644 drivers/virt/coco/sevguest/Kconfig create mode 100644 drivers/virt/coco/sevguest/Makefile create mode 100644 drivers/virt/coco/sevguest/sevguest.c create mode 100644 drivers/virt/coco/sevguest/sevguest.h create mode 100644 include/uapi/linux/sev-guest.h
Documentation/virt/coco/sevguest.rst new file +86 -0
@@ -0,0 +1,86 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================================================== +The Definitive SEV Guest API Documentation +=================================================================== + +1. General description +====================== + +The SEV API is a set of ioctls that are used by the guest or hypervisor +to get or set a certain aspect of the SEV virtual machine. The ioctls belong +to the following classes: + + - Hypervisor ioctls: These query and set global attributes which affect the + whole SEV firmware. These ioctl are used by platform provisioning tools. + + - Guest ioctls: These query and set attributes of the SEV virtual machine. + +2. API description +================== + +This section describes ioctls that is used for querying the SEV guest report +from the SEV firmware. For each ioctl, the following information is provided +along with a description: + + Technology: + which SEV technology provides this ioctl. SEV, SEV-ES, SEV-SNP or all. + + Type: + hypervisor or guest. The ioctl can be used inside the guest or the + hypervisor. + + Parameters: + what parameters are accepted by the ioctl. + + Returns: + the return value. General error numbers (-ENOMEM, -EINVAL) + are not detailed, but errors with specific meanings are. + +The guest ioctl should be issued on a file descriptor of the /dev/sev-guest device. +The ioctl accepts struct snp_user_guest_request. The input and output structure is +specified through the req_data and resp_data field respectively. If the ioctl fails +to execute due to a firmware error, then fw_err code will be set otherwise the +fw_err will be set to 0x00000000000000ff. + +The firmware checks that the message sequence counter is one greater than +the guests message sequence counter. If guest driver fails to increment message +counter (e.g. counter overflow), then -EIO will be returned. + +:: + + struct snp_guest_request_ioctl { + /* Message version number */ + __u32 msg_version; + + /* Request and response structure address */ + __u64 req_data; + __u64 resp_data; + + /* firmware error code on failure (see psp-sev.h) */ + __u64 fw_err; + }; + +2.1 SNP_GET_REPORT +------------------ + +:Technology: sev-snp +:Type: guest ioctl +:Parameters (in): struct snp_report_req +:Returns (out): struct snp_report_resp on success, -negative on error + +The SNP_GET_REPORT ioctl can be used to query the attestation report from the +SEV-SNP firmware. The ioctl uses the SNP_GUEST_REQUEST (MSG_REPORT_REQ) command +provided by the SEV-SNP firmware to query the attestation report. + +On success, the snp_report_resp.data will contains the report. The report +contain the format described in the SEV-SNP specification. See the SEV-SNP +specification for further details. + + +Reference +--------- + +SEV-SNP and GHCB specification: developer.amd.com/sev + +The driver is based on SEV-SNP firmware spec 0.9 and GHCB spec version 2.0.
Documentation/virt/index.rst +1 -0
@@ -13,6 +13,7 @@ Linux Virtualization Support guest-halt-polling ne_overview acrn/index + coco/sevguest .. only:: html and subproject
drivers/virt/Kconfig +3 -0
@@ -47,4 +47,7 @@ source "drivers/virt/vboxguest/Kconfig" source "drivers/virt/nitro_enclaves/Kconfig" source "drivers/virt/acrn/Kconfig" + +source "drivers/virt/coco/sevguest/Kconfig" + endif
drivers/virt/Makefile +1 -0
@@ -9,3 +9,4 @@ obj-y += vboxguest/ obj-$(CONFIG_NITRO_ENCLAVES) += nitro_enclaves/ obj-$(CONFIG_ACRN_HSM) += acrn/ +obj-$(CONFIG_SEV_GUEST) += coco/sevguest/
drivers/virt/coco/sevguest/Kconfig new file +14 -0
@@ -0,0 +1,14 @@ +config SEV_GUEST + tristate "AMD SEV Guest driver" + default m + depends on AMD_MEM_ENCRYPT + select CRYPTO_AEAD2 + select CRYPTO_GCM + help + SEV-SNP firmware provides the guest a mechanism to communicate with + the PSP without risk from a malicious hypervisor who wishes to read, + alter, drop or replay the messages sent. The driver provides + userspace interface to communicate with the PSP to request the + attestation report and more. + + If you choose 'M' here, this module will be called sevguest.
drivers/virt/coco/sevguest/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_SEV_GUEST) += sevguest.o
drivers/virt/coco/sevguest/sevguest.c new file +607 -0
607 lines not on this page · raw message
drivers/virt/coco/sevguest/sevguest.h new file +98 -0
98 lines not on this page · raw message
include/uapi/linux/sev-guest.h new file +50 -0
50 lines not on this page · raw message