Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86/sev: Separate MSR and GHCB based snp_cpuid() via a callback

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

authored by

Ard Biesheuvel and committed by
Borislav Petkov (AMD)
e2e29752 1b237f19

+61 -50
+11 -48
arch/x86/boot/startup/sev-shared.c
··· 342 342 return ret; 343 343 } 344 344 345 - static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 346 - { 347 - u32 cr4 = native_read_cr4(); 348 - int ret; 349 345 350 - ghcb_set_rax(ghcb, leaf->fn); 351 - ghcb_set_rcx(ghcb, leaf->subfn); 352 - 353 - if (cr4 & X86_CR4_OSXSAVE) 354 - /* Safe to read xcr0 */ 355 - ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK)); 356 - else 357 - /* xgetbv will cause #UD - use reset value for xcr0 */ 358 - ghcb_set_xcr0(ghcb, 1); 359 - 360 - ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0); 361 - if (ret != ES_OK) 362 - return ret; 363 - 364 - if (!(ghcb_rax_is_valid(ghcb) && 365 - ghcb_rbx_is_valid(ghcb) && 366 - ghcb_rcx_is_valid(ghcb) && 367 - ghcb_rdx_is_valid(ghcb))) 368 - return ES_VMM_ERROR; 369 - 370 - leaf->eax = ghcb->save.rax; 371 - leaf->ebx = ghcb->save.rbx; 372 - leaf->ecx = ghcb->save.rcx; 373 - leaf->edx = ghcb->save.rdx; 374 - 375 - return ES_OK; 376 - } 377 - 378 - static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 379 - { 380 - return ghcb ? __sev_cpuid_hv_ghcb(ghcb, ctxt, leaf) 381 - : __sev_cpuid_hv_msr(leaf); 382 - } 383 346 384 347 /* 385 348 * This may be called early while still running on the initial identity ··· 447 484 return false; 448 485 } 449 486 450 - static void snp_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 487 + static void snp_cpuid_hv_msr(void *ctx, struct cpuid_leaf *leaf) 451 488 { 452 - if (sev_cpuid_hv(ghcb, ctxt, leaf)) 489 + if (__sev_cpuid_hv_msr(leaf)) 453 490 sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV); 454 491 } 455 492 456 493 static int __head 457 - snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt, 458 - struct cpuid_leaf *leaf) 494 + snp_cpuid_postprocess(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf), 495 + void *ctx, struct cpuid_leaf *leaf) 459 496 { 460 497 struct cpuid_leaf leaf_hv = *leaf; 461 498 462 499 switch (leaf->fn) { 463 500 case 0x1: 464 - snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 501 + cpuid_fn(ctx, &leaf_hv); 465 502 466 503 /* initial APIC ID */ 467 504 leaf->ebx = (leaf_hv.ebx & GENMASK(31, 24)) | (leaf->ebx & GENMASK(23, 0)); ··· 480 517 break; 481 518 case 0xB: 482 519 leaf_hv.subfn = 0; 483 - snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 520 + cpuid_fn(ctx, &leaf_hv); 484 521 485 522 /* extended APIC ID */ 486 523 leaf->edx = leaf_hv.edx; ··· 528 565 } 529 566 break; 530 567 case 0x8000001E: 531 - snp_cpuid_hv(ghcb, ctxt, &leaf_hv); 568 + cpuid_fn(ctx, &leaf_hv); 532 569 533 570 /* extended APIC ID */ 534 571 leaf->eax = leaf_hv.eax; ··· 549 586 * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value 550 587 * should be treated as fatal by caller. 551 588 */ 552 - int __head 553 - snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 589 + int __head snp_cpuid(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf), 590 + void *ctx, struct cpuid_leaf *leaf) 554 591 { 555 592 const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); 556 593 ··· 584 621 return 0; 585 622 } 586 623 587 - return snp_cpuid_postprocess(ghcb, ctxt, leaf); 624 + return snp_cpuid_postprocess(cpuid_fn, ctx, leaf); 588 625 } 589 626 590 627 /* ··· 611 648 leaf.fn = fn; 612 649 leaf.subfn = subfn; 613 650 614 - ret = snp_cpuid(NULL, NULL, &leaf); 651 + ret = snp_cpuid(snp_cpuid_hv_msr, NULL, &leaf); 615 652 if (!ret) 616 653 goto cpuid_done; 617 654
+48 -1
arch/x86/coco/sev/vc-shared.c
··· 409 409 return ret; 410 410 } 411 411 412 + static int __sev_cpuid_hv_ghcb(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) 413 + { 414 + u32 cr4 = native_read_cr4(); 415 + int ret; 416 + 417 + ghcb_set_rax(ghcb, leaf->fn); 418 + ghcb_set_rcx(ghcb, leaf->subfn); 419 + 420 + if (cr4 & X86_CR4_OSXSAVE) 421 + /* Safe to read xcr0 */ 422 + ghcb_set_xcr0(ghcb, xgetbv(XCR_XFEATURE_ENABLED_MASK)); 423 + else 424 + /* xgetbv will cause #UD - use reset value for xcr0 */ 425 + ghcb_set_xcr0(ghcb, 1); 426 + 427 + ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0); 428 + if (ret != ES_OK) 429 + return ret; 430 + 431 + if (!(ghcb_rax_is_valid(ghcb) && 432 + ghcb_rbx_is_valid(ghcb) && 433 + ghcb_rcx_is_valid(ghcb) && 434 + ghcb_rdx_is_valid(ghcb))) 435 + return ES_VMM_ERROR; 436 + 437 + leaf->eax = ghcb->save.rax; 438 + leaf->ebx = ghcb->save.rbx; 439 + leaf->ecx = ghcb->save.rcx; 440 + leaf->edx = ghcb->save.rdx; 441 + 442 + return ES_OK; 443 + } 444 + 445 + struct cpuid_ctx { 446 + struct ghcb *ghcb; 447 + struct es_em_ctxt *ctxt; 448 + }; 449 + 450 + static void snp_cpuid_hv_ghcb(void *p, struct cpuid_leaf *leaf) 451 + { 452 + struct cpuid_ctx *ctx = p; 453 + 454 + if (__sev_cpuid_hv_ghcb(ctx->ghcb, ctx->ctxt, leaf)) 455 + sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID_HV); 456 + } 457 + 412 458 static int vc_handle_cpuid_snp(struct ghcb *ghcb, struct es_em_ctxt *ctxt) 413 459 { 460 + struct cpuid_ctx ctx = { ghcb, ctxt }; 414 461 struct pt_regs *regs = ctxt->regs; 415 462 struct cpuid_leaf leaf; 416 463 int ret; 417 464 418 465 leaf.fn = regs->ax; 419 466 leaf.subfn = regs->cx; 420 - ret = snp_cpuid(ghcb, ctxt, &leaf); 467 + ret = snp_cpuid(snp_cpuid_hv_ghcb, &ctx, &leaf); 421 468 if (!ret) { 422 469 regs->ax = leaf.eax; 423 470 regs->bx = leaf.ebx;
+2 -1
arch/x86/include/asm/sev.h
··· 552 552 u32 edx; 553 553 }; 554 554 555 - int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf); 555 + int snp_cpuid(void (*cpuid_fn)(void *ctx, struct cpuid_leaf *leaf), 556 + void *ctx, struct cpuid_leaf *leaf); 556 557 557 558 void __noreturn sev_es_terminate(unsigned int set, unsigned int reason); 558 559 enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,