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

x86/sev: Add full support for a segmented RMP table

A segmented RMP table allows for improved locality of reference between
the memory protected by the RMP and the RMP entries themselves.

Add support to detect and initialize a segmented RMP table with multiple
segments as configured by the system BIOS. While the RMPREAD instruction
will be used to read an RMP entry in a segmented RMP, initialization and
debugging capabilities will require the mapping of the segments.

The RMP_CFG MSR indicates if segmented RMP support is enabled and, if
enabled, the amount of memory that an RMP segment covers. When segmented
RMP support is enabled, the RMP_BASE MSR points to the start of the RMP
bookkeeping area, which is 16K in size. The RMP Segment Table (RST) is
located immediately after the bookkeeping area and is 4K in size. The RST
contains up to 512 8-byte entries that identify the location of the RMP
segment and amount of memory mapped by the segment (which must be less
than or equal to the configured segment size). The physical address that
is covered by a segment is based on the segment size and the index of the
segment in the RST. The RMP entry for a physical address is based on the
offset within the segment.

For example, if the segment size is 64GB (0x1000000000 or 1 << 36), then
physical address 0x9000800000 is RST entry 9 (0x9000800000 >> 36) and
RST entry 9 covers physical memory 0x9000000000 to 0x9FFFFFFFFF.

The RMP entry index within the RMP segment is the physical address
AND-ed with the segment mask, 64GB - 1 (0xFFFFFFFFF), and then
right-shifted 12 bits or PHYS_PFN(0x9000800000 & 0xFFFFFFFFF), which
is 0x800.

CPUID 0x80000025_EBX[9:0] describes the number of RMP segments that can
be cached by the hardware. Additionally, if CPUID 0x80000025_EBX[10] is
set, then the number of actual RMP segments defined cannot exceed the
number of RMP segments that can be cached and can be used as a maximum
RST index.

[ bp: Unify printk hex format specifiers. ]

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Nikunj A Dadhania <nikunj@amd.com>
Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Link: https://lore.kernel.org/r/02afd0ffd097a19cb6e5fb1bb76eb110496c5b11.1734101742.git.thomas.lendacky@amd.com

authored by

Tom Lendacky and committed by
Borislav Petkov (AMD)
8ae3291f 0f14af0d

+245 -24
+1
arch/x86/include/asm/cpufeatures.h
··· 452 452 #define X86_FEATURE_SME_COHERENT (19*32+10) /* AMD hardware-enforced cache coherency */ 453 453 #define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" AMD SEV-ES full debug state swap support */ 454 454 #define X86_FEATURE_RMPREAD (19*32+21) /* RMPREAD instruction */ 455 + #define X86_FEATURE_SEGMENTED_RMP (19*32+23) /* Segmented RMP support */ 455 456 #define X86_FEATURE_SVSM (19*32+28) /* "svsm" SVSM present */ 456 457 457 458 /* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */
+5 -3
arch/x86/include/asm/msr-index.h
··· 644 644 #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ 645 645 #define MSR_AMD64_SVM_AVIC_DOORBELL 0xc001011b 646 646 #define MSR_AMD64_VM_PAGE_FLUSH 0xc001011e 647 + #define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f 647 648 #define MSR_AMD64_SEV_ES_GHCB 0xc0010130 648 649 #define MSR_AMD64_SEV 0xc0010131 649 650 #define MSR_AMD64_SEV_ENABLED_BIT 0 ··· 683 682 #define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT) 684 683 #define MSR_AMD64_SNP_RESV_BIT 18 685 684 #define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, MSR_AMD64_SNP_RESV_BIT) 686 - 687 - #define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f 688 - 689 685 #define MSR_AMD64_RMP_BASE 0xc0010132 690 686 #define MSR_AMD64_RMP_END 0xc0010133 687 + #define MSR_AMD64_RMP_CFG 0xc0010136 688 + #define MSR_AMD64_SEG_RMP_ENABLED_BIT 0 689 + #define MSR_AMD64_SEG_RMP_ENABLED BIT_ULL(MSR_AMD64_SEG_RMP_ENABLED_BIT) 690 + #define MSR_AMD64_RMP_SEGMENT_SHIFT(x) (((x) & GENMASK_ULL(13, 8)) >> 8) 691 691 692 692 #define MSR_SVSM_CAA 0xc001f000 693 693
+239 -21
arch/x86/virt/svm/sev.c
··· 100 100 * a specific portion of memory. There can be up to 512 8-byte entries, 101 101 * one pages worth. 102 102 */ 103 + #define RST_ENTRY_MAPPED_SIZE(x) ((x) & GENMASK_ULL(19, 0)) 104 + #define RST_ENTRY_SEGMENT_BASE(x) ((x) & GENMASK_ULL(51, 20)) 105 + 106 + #define RST_SIZE SZ_4K 103 107 static struct rmp_segment_desc **rmp_segment_table __ro_after_init; 104 108 static unsigned int rst_max_index __ro_after_init = 512; 105 109 ··· 113 109 114 110 #define RST_ENTRY_INDEX(x) ((x) >> rmp_segment_shift) 115 111 #define RMP_ENTRY_INDEX(x) ((u64)(PHYS_PFN((x) & rmp_segment_mask))) 112 + 113 + static u64 rmp_cfg; 116 114 117 115 /* Mask to apply to a PFN to get the first PFN of a 2MB page */ 118 116 #define PFN_PMD_MASK GENMASK_ULL(63, PMD_SHIFT - PAGE_SHIFT) ··· 204 198 } 205 199 } 206 200 207 - void __init snp_fixup_e820_tables(void) 201 + static void __init fixup_e820_tables_for_segmented_rmp(void) 202 + { 203 + u64 pa, *rst, size, mapped_size; 204 + unsigned int i; 205 + 206 + __snp_fixup_e820_tables(probed_rmp_base); 207 + 208 + pa = probed_rmp_base + RMPTABLE_CPU_BOOKKEEPING_SZ; 209 + 210 + __snp_fixup_e820_tables(pa + RST_SIZE); 211 + 212 + rst = early_memremap(pa, RST_SIZE); 213 + if (!rst) 214 + return; 215 + 216 + for (i = 0; i < rst_max_index; i++) { 217 + pa = RST_ENTRY_SEGMENT_BASE(rst[i]); 218 + mapped_size = RST_ENTRY_MAPPED_SIZE(rst[i]); 219 + if (!mapped_size) 220 + continue; 221 + 222 + __snp_fixup_e820_tables(pa); 223 + 224 + /* 225 + * Mapped size in GB. Mapped size is allowed to exceed 226 + * the segment coverage size, but gets reduced to the 227 + * segment coverage size. 228 + */ 229 + mapped_size <<= 30; 230 + if (mapped_size > rmp_segment_size) 231 + mapped_size = rmp_segment_size; 232 + 233 + /* Calculate the RMP segment size (16 bytes/page mapped) */ 234 + size = PHYS_PFN(mapped_size) << 4; 235 + 236 + __snp_fixup_e820_tables(pa + size); 237 + } 238 + 239 + early_memunmap(rst, RST_SIZE); 240 + } 241 + 242 + static void __init fixup_e820_tables_for_contiguous_rmp(void) 208 243 { 209 244 __snp_fixup_e820_tables(probed_rmp_base); 210 245 __snp_fixup_e820_tables(probed_rmp_base + probed_rmp_size); 246 + } 247 + 248 + void __init snp_fixup_e820_tables(void) 249 + { 250 + if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) { 251 + fixup_e820_tables_for_segmented_rmp(); 252 + } else { 253 + fixup_e820_tables_for_contiguous_rmp(); 254 + } 211 255 } 212 256 213 257 static bool __init clear_rmptable_bookkeeping(void) ··· 363 307 return true; 364 308 } 365 309 366 - /* 367 - * Do the necessary preparations which are verified by the firmware as 368 - * described in the SNP_INIT_EX firmware command description in the SNP 369 - * firmware ABI spec. 370 - */ 371 - static int __init snp_rmptable_init(void) 310 + static bool __init setup_contiguous_rmptable(void) 372 311 { 373 - u64 max_rmp_pfn, calc_rmp_sz, rmptable_segment, rmptable_size, rmp_end, val; 374 - unsigned int i; 375 - 376 - if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) 377 - return 0; 378 - 379 - if (!amd_iommu_snp_en) 380 - goto nosnp; 312 + u64 max_rmp_pfn, calc_rmp_sz, rmptable_segment, rmptable_size, rmp_end; 381 313 382 314 if (!probed_rmp_size) 383 - goto nosnp; 315 + return false; 384 316 385 317 rmp_end = probed_rmp_base + probed_rmp_size - 1; 386 318 387 319 /* 388 - * Calculate the amount the memory that must be reserved by the BIOS to 320 + * Calculate the amount of memory that must be reserved by the BIOS to 389 321 * address the whole RAM, including the bookkeeping area. The RMP itself 390 322 * must also be covered. 391 323 */ ··· 385 341 if (calc_rmp_sz > probed_rmp_size) { 386 342 pr_err("Memory reserved for the RMP table does not cover full system RAM (expected 0x%llx got 0x%llx)\n", 387 343 calc_rmp_sz, probed_rmp_size); 388 - goto nosnp; 344 + return false; 389 345 } 390 346 391 347 if (!alloc_rmp_segment_table()) 392 - goto nosnp; 348 + return false; 393 349 394 350 /* Map only the RMP entries */ 395 351 rmptable_segment = probed_rmp_base + RMPTABLE_CPU_BOOKKEEPING_SZ; ··· 397 353 398 354 if (!alloc_rmp_segment_desc(rmptable_segment, rmptable_size, 0)) { 399 355 free_rmp_segment_table(); 400 - goto nosnp; 356 + return false; 401 357 } 358 + 359 + return true; 360 + } 361 + 362 + static bool __init setup_segmented_rmptable(void) 363 + { 364 + u64 rst_pa, *rst, pa, ram_pa_end, ram_pa_max; 365 + unsigned int i, max_index; 366 + 367 + if (!probed_rmp_base) 368 + return false; 369 + 370 + if (!alloc_rmp_segment_table()) 371 + return false; 372 + 373 + rst_pa = probed_rmp_base + RMPTABLE_CPU_BOOKKEEPING_SZ; 374 + rst = memremap(rst_pa, RST_SIZE, MEMREMAP_WB); 375 + if (!rst) { 376 + pr_err("Failed to map RMP segment table addr 0x%llx\n", rst_pa); 377 + goto e_free; 378 + } 379 + 380 + pr_info("Segmented RMP using %lluGB segments\n", rmp_segment_size >> 30); 381 + 382 + ram_pa_max = max_pfn << PAGE_SHIFT; 383 + 384 + max_index = 0; 385 + ram_pa_end = 0; 386 + for (i = 0; i < rst_max_index; i++) { 387 + u64 rmp_segment, rmp_size, mapped_size; 388 + 389 + mapped_size = RST_ENTRY_MAPPED_SIZE(rst[i]); 390 + if (!mapped_size) 391 + continue; 392 + 393 + max_index = i; 394 + 395 + /* 396 + * Mapped size in GB. Mapped size is allowed to exceed the 397 + * segment coverage size, but gets reduced to the segment 398 + * coverage size. 399 + */ 400 + mapped_size <<= 30; 401 + if (mapped_size > rmp_segment_size) { 402 + pr_info("RMP segment %u mapped size (0x%llx) reduced to 0x%llx\n", 403 + i, mapped_size, rmp_segment_size); 404 + mapped_size = rmp_segment_size; 405 + } 406 + 407 + rmp_segment = RST_ENTRY_SEGMENT_BASE(rst[i]); 408 + 409 + /* Calculate the RMP segment size (16 bytes/page mapped) */ 410 + rmp_size = PHYS_PFN(mapped_size) << 4; 411 + 412 + pa = (u64)i << rmp_segment_shift; 413 + 414 + /* 415 + * Some segments may be for MMIO mapped above system RAM. These 416 + * segments are used for Trusted I/O. 417 + */ 418 + if (pa < ram_pa_max) 419 + ram_pa_end = pa + mapped_size; 420 + 421 + if (!alloc_rmp_segment_desc(rmp_segment, rmp_size, pa)) 422 + goto e_unmap; 423 + 424 + pr_info("RMP segment %u physical address [0x%llx - 0x%llx] covering [0x%llx - 0x%llx]\n", 425 + i, rmp_segment, rmp_segment + rmp_size - 1, pa, pa + mapped_size - 1); 426 + } 427 + 428 + if (ram_pa_max > ram_pa_end) { 429 + pr_err("Segmented RMP does not cover full system RAM (expected 0x%llx got 0x%llx)\n", 430 + ram_pa_max, ram_pa_end); 431 + goto e_unmap; 432 + } 433 + 434 + /* Adjust the maximum index based on the found segments */ 435 + rst_max_index = max_index + 1; 436 + 437 + memunmap(rst); 438 + 439 + return true; 440 + 441 + e_unmap: 442 + memunmap(rst); 443 + 444 + e_free: 445 + free_rmp_segment_table(); 446 + 447 + return false; 448 + } 449 + 450 + static bool __init setup_rmptable(void) 451 + { 452 + if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) { 453 + return setup_segmented_rmptable(); 454 + } else { 455 + return setup_contiguous_rmptable(); 456 + } 457 + } 458 + 459 + /* 460 + * Do the necessary preparations which are verified by the firmware as 461 + * described in the SNP_INIT_EX firmware command description in the SNP 462 + * firmware ABI spec. 463 + */ 464 + static int __init snp_rmptable_init(void) 465 + { 466 + unsigned int i; 467 + u64 val; 468 + 469 + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) 470 + return 0; 471 + 472 + if (!amd_iommu_snp_en) 473 + goto nosnp; 474 + 475 + if (!setup_rmptable()) 476 + goto nosnp; 402 477 403 478 /* 404 479 * Check if SEV-SNP is already enabled, this can happen in case of ··· 582 419 583 420 #define RMP_ADDR_MASK GENMASK_ULL(51, 13) 584 421 585 - bool snp_probe_rmptable_info(void) 422 + static bool probe_contiguous_rmptable_info(void) 586 423 { 587 424 u64 rmp_sz, rmp_base, rmp_end; 588 425 ··· 613 450 rmp_base, rmp_end); 614 451 615 452 return true; 453 + } 454 + 455 + static bool probe_segmented_rmptable_info(void) 456 + { 457 + unsigned int eax, ebx, segment_shift, segment_shift_min, segment_shift_max; 458 + u64 rmp_base, rmp_end; 459 + 460 + rdmsrl(MSR_AMD64_RMP_BASE, rmp_base); 461 + if (!(rmp_base & RMP_ADDR_MASK)) { 462 + pr_err("Memory for the RMP table has not been reserved by BIOS\n"); 463 + return false; 464 + } 465 + 466 + rdmsrl(MSR_AMD64_RMP_END, rmp_end); 467 + WARN_ONCE(rmp_end & RMP_ADDR_MASK, 468 + "Segmented RMP enabled but RMP_END MSR is non-zero\n"); 469 + 470 + /* Obtain the min and max supported RMP segment size */ 471 + eax = cpuid_eax(0x80000025); 472 + segment_shift_min = eax & GENMASK(5, 0); 473 + segment_shift_max = (eax & GENMASK(11, 6)) >> 6; 474 + 475 + /* Verify the segment size is within the supported limits */ 476 + segment_shift = MSR_AMD64_RMP_SEGMENT_SHIFT(rmp_cfg); 477 + if (segment_shift > segment_shift_max || segment_shift < segment_shift_min) { 478 + pr_err("RMP segment size (%u) is not within advertised bounds (min=%u, max=%u)\n", 479 + segment_shift, segment_shift_min, segment_shift_max); 480 + return false; 481 + } 482 + 483 + /* Override the max supported RST index if a hardware limit exists */ 484 + ebx = cpuid_ebx(0x80000025); 485 + if (ebx & BIT(10)) 486 + rst_max_index = ebx & GENMASK(9, 0); 487 + 488 + set_rmp_segment_info(segment_shift); 489 + 490 + probed_rmp_base = rmp_base; 491 + probed_rmp_size = 0; 492 + 493 + pr_info("Segmented RMP base table physical range [0x%016llx - 0x%016llx]\n", 494 + rmp_base, rmp_base + RMPTABLE_CPU_BOOKKEEPING_SZ + RST_SIZE); 495 + 496 + return true; 497 + } 498 + 499 + bool snp_probe_rmptable_info(void) 500 + { 501 + if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) 502 + rdmsrl(MSR_AMD64_RMP_CFG, rmp_cfg); 503 + 504 + if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) 505 + return probe_segmented_rmptable_info(); 506 + else 507 + return probe_contiguous_rmptable_info(); 616 508 } 617 509 618 510 /*