]> www.infradead.org Git - users/hch/misc.git/commitdiff
x86/sev: Separate MSR and GHCB based snp_cpuid() via a callback
authorArd Biesheuvel <ardb@kernel.org>
Thu, 28 Aug 2025 10:22:04 +0000 (12:22 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Thu, 28 Aug 2025 14:52:05 +0000 (16:52 +0200)
There are two distinct callers of snp_cpuid(): the MSR protocol and the GHCB
page based interface.

The snp_cpuid() logic does not care about the distinction, which only matters
at a lower level. But the fact that it supports both interfaces means that the
GHCB page based logic is pulled into the early startup code where PA to VA
conversions are problematic, given that it runs from the 1:1 mapping of memory.

So keep snp_cpuid() itself in the startup code, but factor out the hypervisor
calls via a callback, so that the GHCB page handling can be moved out.

Code refactoring only - no functional change intended.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Link: https://lore.kernel.org/20250828102202.1849035-25-ardb+git@google.com
arch/x86/boot/startup/sev-shared.c
arch/x86/coco/sev/vc-shared.c
arch/x86/include/asm/sev.h

index a34cd19796f9ac6ec8b17cd8efe90111bebdff3c..ed88dfe7605e53f7cbd5eaaa113efb1ac5de0f3f 100644 (file)
@@ -342,44 +342,7 @@ static int __sev_cpuid_hv_msr(struct cpuid_leaf *leaf)
        return ret;
 }
 
-static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
-{
-       u32 cr4 = native_read_cr4();
-       int ret;
-
-       ghcb_set_rax(ghcb, leaf->fn);
-       ghcb_set_rcx(ghcb, leaf->subfn);
-
-       if (cr4 & X86_CR4_OSXSAVE)
-               /* Safe to read xcr0 */
-               ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK));
-       else
-               /* xgetbv will cause #UD - use reset value for xcr0 */
-               ghcb_set_xcr0(ghcb, 1);
-
-       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0);
-       if (ret != ES_OK)
-               return ret;
-
-       if (!(ghcb_rax_is_valid(ghcb) &&
-             ghcb_rbx_is_valid(ghcb) &&
-             ghcb_rcx_is_valid(ghcb) &&
-             ghcb_rdx_is_valid(ghcb)))
-               return ES_VMM_ERROR;
 
-       leaf->eax = ghcb->save.rax;
-       leaf->ebx = ghcb->save.rbx;
-       leaf->ecx = ghcb->save.rcx;
-       leaf->edx = ghcb->save.rdx;
-
-       return ES_OK;
-}
-
-static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
-{
-       return ghcb ? __sev_cpuid_hv_ghcb(ghcb, ctxt, leaf)
-                   : __sev_cpuid_hv_msr(leaf);
-}
 
 /*
  * This may be called early while still running on the initial identity
@@ -484,21 +447,21 @@ snp_cpuid_get_validated_func(struct cpuid_leaf *leaf)
        return false;
 }
 
-static void snp_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+static void snp_cpuid_hv_msr(void *ctx, struct cpuid_leaf *leaf)
 {
-       if (sev_cpuid_hv(ghcb, ctxt, leaf))
+       if (__sev_cpuid_hv_msr(leaf))
                sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV);
 }
 
 static int __head
-snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
-                     struct cpuid_leaf *leaf)
+snp_cpuid_postprocess(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf),
+                     void *ctx, struct cpuid_leaf *leaf)
 {
        struct cpuid_leaf leaf_hv = *leaf;
 
        switch (leaf->fn) {
        case 0x1:
-               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
+               cpuid_fn(ctx, &leaf_hv);
 
                /* initial APIC ID */
                leaf->ebx = (leaf_hv.ebx & GENMASK(31, 24)) | (leaf->ebx & GENMASK(23, 0));
@@ -517,7 +480,7 @@ snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
                break;
        case 0xB:
                leaf_hv.subfn = 0;
-               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
+               cpuid_fn(ctx, &leaf_hv);
 
                /* extended APIC ID */
                leaf->edx = leaf_hv.edx;
@@ -565,7 +528,7 @@ snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
                }
                break;
        case 0x8000001E:
-               snp_cpuid_hv(ghcb, ctxt, &leaf_hv);
+               cpuid_fn(ctx, &leaf_hv);
 
                /* extended APIC ID */
                leaf->eax = leaf_hv.eax;
@@ -586,8 +549,8 @@ snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
  * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value
  * should be treated as fatal by caller.
  */
-int __head
-snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+int __head snp_cpuid(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf),
+                    void *ctx, struct cpuid_leaf *leaf)
 {
        const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
 
@@ -621,7 +584,7 @@ snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
                        return 0;
        }
 
-       return snp_cpuid_postprocess(ghcb, ctxt, leaf);
+       return snp_cpuid_postprocess(cpuid_fn, ctx, leaf);
 }
 
 /*
@@ -648,7 +611,7 @@ void __head do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
        leaf.fn = fn;
        leaf.subfn = subfn;
 
-       ret = snp_cpuid(NULL, NULL, &leaf);
+       ret = snp_cpuid(snp_cpuid_hv_msr, NULL, &leaf);
        if (!ret)
                goto cpuid_done;
 
index 2c0ab0fdc0603e4409e547bd247f2874666c3bd4..b4688f69102e26f782d2e027b0ed8d16e58f2a02 100644 (file)
@@ -409,15 +409,62 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
        return ret;
 }
 
+static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+{
+       u32 cr4 = native_read_cr4();
+       int ret;
+
+       ghcb_set_rax(ghcb, leaf->fn);
+       ghcb_set_rcx(ghcb, leaf->subfn);
+
+       if (cr4 & X86_CR4_OSXSAVE)
+               /* Safe to read xcr0 */
+               ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK));
+       else
+               /* xgetbv will cause #UD - use reset value for xcr0 */
+               ghcb_set_xcr0(ghcb, 1);
+
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0);
+       if (ret != ES_OK)
+               return ret;
+
+       if (!(ghcb_rax_is_valid(ghcb) &&
+             ghcb_rbx_is_valid(ghcb) &&
+             ghcb_rcx_is_valid(ghcb) &&
+             ghcb_rdx_is_valid(ghcb)))
+               return ES_VMM_ERROR;
+
+       leaf->eax = ghcb->save.rax;
+       leaf->ebx = ghcb->save.rbx;
+       leaf->ecx = ghcb->save.rcx;
+       leaf->edx = ghcb->save.rdx;
+
+       return ES_OK;
+}
+
+struct cpuid_ctx {
+       struct ghcb *ghcb;
+       struct es_em_ctxt *ctxt;
+};
+
+static void snp_cpuid_hv_ghcb(void *p, struct cpuid_leaf *leaf)
+{
+       struct cpuid_ctx *ctx = p;
+
+       if (__sev_cpuid_hv_ghcb(ctx->ghcb, ctx->ctxt, leaf))
+               sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV);
+}
+
 static int vc_handle_cpuid_snp(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
 {
+       struct cpuid_ctx ctx = { ghcb, ctxt };
        struct pt_regs *regs = ctxt->regs;
        struct cpuid_leaf leaf;
        int ret;
 
        leaf.fn = regs->ax;
        leaf.subfn = regs->cx;
-       ret = snp_cpuid(ghcb, ctxt, &leaf);
+       ret = snp_cpuid(snp_cpuid_hv_ghcb, &ctx, &leaf);
        if (!ret) {
                regs->ax = leaf.eax;
                regs->bx = leaf.ebx;
index 02236962fdb108009e419e010d3862688e1f694d..e4622e470ceb91012f6d6b4af96f80611bf7e145 100644 (file)
@@ -552,7 +552,8 @@ struct cpuid_leaf {
        u32 edx;
 };
 
-int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf);
+int snp_cpuid(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf),
+             void *ctx, struct cpuid_leaf *leaf);
 
 void __noreturn sev_es_terminate(unsigned int set, unsigned int reason);
 enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,