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

Merge remote-tracking branch 'tip/x86/sev' into hyperv-next

Merge the following 6 patches from tip/x86/sev, which are taken from
Michael Kelley's series [0]. The rest of Michael's series depend on
them.

x86/hyperv: Change vTOM handling to use standard coco mechanisms
init: Call mem_encrypt_init() after Hyper-V hypercall init is done
x86/mm: Handle decryption/re-encryption of bss_decrypted consistently
Drivers: hv: Explicitly request decrypted in vmap_pfn() calls
x86/hyperv: Reorder code to facilitate future work
x86/ioremap: Add hypervisor callback for private MMIO mapping in coco VM

0: https://lore.kernel.org/linux-hyperv/1679838727-87310-1-git-send-email-mikelley@microsoft.com/

Wei Liu 21eb596f f83705a5

+335 -180
+13 -7
Documentation/virt/coco/sev-guest.rst
··· 37 37 the return value. General error numbers (-ENOMEM, -EINVAL) 38 38 are not detailed, but errors with specific meanings are. 39 39 40 - The guest ioctl should be issued on a file descriptor of the /dev/sev-guest device. 41 - The ioctl accepts struct snp_user_guest_request. The input and output structure is 42 - specified through the req_data and resp_data field respectively. If the ioctl fails 43 - to execute due to a firmware error, then fw_err code will be set otherwise the 44 - fw_err will be set to 0x00000000000000ff. 40 + The guest ioctl should be issued on a file descriptor of the /dev/sev-guest 41 + device. The ioctl accepts struct snp_user_guest_request. The input and 42 + output structure is specified through the req_data and resp_data field 43 + respectively. If the ioctl fails to execute due to a firmware error, then 44 + the fw_error code will be set, otherwise fw_error will be set to -1. 45 45 46 46 The firmware checks that the message sequence counter is one greater than 47 47 the guests message sequence counter. If guest driver fails to increment message ··· 57 57 __u64 req_data; 58 58 __u64 resp_data; 59 59 60 - /* firmware error code on failure (see psp-sev.h) */ 61 - __u64 fw_err; 60 + /* bits[63:32]: VMM error code, bits[31:0] firmware error code (see psp-sev.h) */ 61 + union { 62 + __u64 exitinfo2; 63 + struct { 64 + __u32 fw_error; 65 + __u32 vmm_error; 66 + }; 67 + }; 62 68 }; 63 69 64 70 2.1 SNP_GET_REPORT
+34 -19
arch/x86/coco/core.c
··· 13 13 #include <asm/coco.h> 14 14 #include <asm/processor.h> 15 15 16 - static enum cc_vendor vendor __ro_after_init; 16 + enum cc_vendor cc_vendor __ro_after_init; 17 17 static u64 cc_mask __ro_after_init; 18 18 19 19 static bool intel_cc_platform_has(enum cc_attr attr) ··· 21 21 switch (attr) { 22 22 case CC_ATTR_GUEST_UNROLL_STRING_IO: 23 23 case CC_ATTR_HOTPLUG_DISABLED: 24 + case CC_ATTR_GUEST_MEM_ENCRYPT: 25 + case CC_ATTR_MEM_ENCRYPT: 26 + return true; 27 + default: 28 + return false; 29 + } 30 + } 31 + 32 + /* 33 + * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and 34 + * the other levels of SME/SEV functionality, including C-bit 35 + * based SEV-SNP, are not enabled. 36 + */ 37 + static __maybe_unused bool amd_cc_platform_vtom(enum cc_attr attr) 38 + { 39 + switch (attr) { 24 40 case CC_ATTR_GUEST_MEM_ENCRYPT: 25 41 case CC_ATTR_MEM_ENCRYPT: 26 42 return true; ··· 57 41 * up under SME the trampoline area cannot be encrypted, whereas under SEV 58 42 * the trampoline area must be encrypted. 59 43 */ 44 + 60 45 static bool amd_cc_platform_has(enum cc_attr attr) 61 46 { 62 47 #ifdef CONFIG_AMD_MEM_ENCRYPT 48 + 49 + if (sev_status & MSR_AMD64_SNP_VTOM) 50 + return amd_cc_platform_vtom(attr); 51 + 63 52 switch (attr) { 64 53 case CC_ATTR_MEM_ENCRYPT: 65 54 return sme_me_mask; ··· 97 76 #endif 98 77 } 99 78 100 - static bool hyperv_cc_platform_has(enum cc_attr attr) 101 - { 102 - return attr == CC_ATTR_GUEST_MEM_ENCRYPT; 103 - } 104 - 105 79 bool cc_platform_has(enum cc_attr attr) 106 80 { 107 - switch (vendor) { 81 + switch (cc_vendor) { 108 82 case CC_VENDOR_AMD: 109 83 return amd_cc_platform_has(attr); 110 84 case CC_VENDOR_INTEL: 111 85 return intel_cc_platform_has(attr); 112 - case CC_VENDOR_HYPERV: 113 - return hyperv_cc_platform_has(attr); 114 86 default: 115 87 return false; 116 88 } ··· 117 103 * encryption status of the page. 118 104 * 119 105 * - for AMD, bit *set* means the page is encrypted 120 - * - for Intel *clear* means encrypted. 106 + * - for AMD with vTOM and for Intel, *clear* means encrypted 121 107 */ 122 - switch (vendor) { 108 + switch (cc_vendor) { 123 109 case CC_VENDOR_AMD: 124 - return val | cc_mask; 110 + if (sev_status & MSR_AMD64_SNP_VTOM) 111 + return val & ~cc_mask; 112 + else 113 + return val | cc_mask; 125 114 case CC_VENDOR_INTEL: 126 115 return val & ~cc_mask; 127 116 default: ··· 135 118 u64 cc_mkdec(u64 val) 136 119 { 137 120 /* See comment in cc_mkenc() */ 138 - switch (vendor) { 121 + switch (cc_vendor) { 139 122 case CC_VENDOR_AMD: 140 - return val & ~cc_mask; 123 + if (sev_status & MSR_AMD64_SNP_VTOM) 124 + return val | cc_mask; 125 + else 126 + return val & ~cc_mask; 141 127 case CC_VENDOR_INTEL: 142 128 return val | cc_mask; 143 129 default: ··· 148 128 } 149 129 } 150 130 EXPORT_SYMBOL_GPL(cc_mkdec); 151 - 152 - __init void cc_set_vendor(enum cc_vendor v) 153 - { 154 - vendor = v; 155 - } 156 131 157 132 __init void cc_set_mask(u64 mask) 158 133 {
-11
arch/x86/hyperv/hv_init.c
··· 29 29 #include <linux/syscore_ops.h> 30 30 #include <clocksource/hyperv_timer.h> 31 31 #include <linux/highmem.h> 32 - #include <linux/swiotlb.h> 33 32 34 33 int hyperv_init_cpuhp; 35 34 u64 hv_current_partition_id = ~0ull; ··· 502 503 503 504 /* Query the VMs extended capability once, so that it can be cached. */ 504 505 hv_query_ext_cap(0); 505 - 506 - #ifdef CONFIG_SWIOTLB 507 - /* 508 - * Swiotlb bounce buffer needs to be mapped in extra address 509 - * space. Map function doesn't work in the early place and so 510 - * call swiotlb_update_mem_attributes() here. 511 - */ 512 - if (hv_is_isolation_supported()) 513 - swiotlb_update_mem_attributes(); 514 - #endif 515 506 516 507 return; 517 508
+96 -46
arch/x86/hyperv/ivm.c
··· 13 13 #include <asm/svm.h> 14 14 #include <asm/sev.h> 15 15 #include <asm/io.h> 16 + #include <asm/coco.h> 17 + #include <asm/mem_encrypt.h> 16 18 #include <asm/mshyperv.h> 17 19 #include <asm/hypervisor.h> 18 20 ··· 235 233 local_irq_restore(flags); 236 234 } 237 235 EXPORT_SYMBOL_GPL(hv_ghcb_msr_read); 238 - #endif 239 - 240 - enum hv_isolation_type hv_get_isolation_type(void) 241 - { 242 - if (!(ms_hyperv.priv_high & HV_ISOLATION)) 243 - return HV_ISOLATION_TYPE_NONE; 244 - return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); 245 - } 246 - EXPORT_SYMBOL_GPL(hv_get_isolation_type); 247 - 248 - /* 249 - * hv_is_isolation_supported - Check system runs in the Hyper-V 250 - * isolation VM. 251 - */ 252 - bool hv_is_isolation_supported(void) 253 - { 254 - if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) 255 - return false; 256 - 257 - if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) 258 - return false; 259 - 260 - return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; 261 - } 262 - 263 - DEFINE_STATIC_KEY_FALSE(isolation_type_snp); 264 - 265 - /* 266 - * hv_isolation_type_snp - Check system runs in the AMD SEV-SNP based 267 - * isolation VM. 268 - */ 269 - bool hv_isolation_type_snp(void) 270 - { 271 - return static_branch_unlikely(&isolation_type_snp); 272 - } 273 236 274 237 /* 275 238 * hv_mark_gpa_visibility - Set pages visible to host via hvcall. ··· 287 320 } 288 321 289 322 /* 290 - * hv_set_mem_host_visibility - Set specified memory visible to host. 323 + * hv_vtom_set_host_visibility - Set specified memory visible to host. 291 324 * 292 325 * In Isolation VM, all guest memory is encrypted from host and guest 293 326 * needs to set memory visible to host via hvcall before sharing memory 294 327 * with host. This function works as wrap of hv_mark_gpa_visibility() 295 328 * with memory base and size. 296 329 */ 297 - int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visible) 330 + static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bool enc) 298 331 { 299 - enum hv_mem_host_visibility visibility = visible ? 300 - VMBUS_PAGE_VISIBLE_READ_WRITE : VMBUS_PAGE_NOT_VISIBLE; 332 + enum hv_mem_host_visibility visibility = enc ? 333 + VMBUS_PAGE_NOT_VISIBLE : VMBUS_PAGE_VISIBLE_READ_WRITE; 301 334 u64 *pfn_array; 302 335 int ret = 0; 336 + bool result = true; 303 337 int i, pfn; 304 - 305 - if (!hv_is_isolation_supported() || !hv_hypercall_pg) 306 - return 0; 307 338 308 339 pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); 309 340 if (!pfn_array) 310 - return -ENOMEM; 341 + return false; 311 342 312 343 for (i = 0, pfn = 0; i < pagecount; i++) { 313 344 pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE); ··· 314 349 if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) { 315 350 ret = hv_mark_gpa_visibility(pfn, pfn_array, 316 351 visibility); 317 - if (ret) 352 + if (ret) { 353 + result = false; 318 354 goto err_free_pfn_array; 355 + } 319 356 pfn = 0; 320 357 } 321 358 } 322 359 323 360 err_free_pfn_array: 324 361 kfree(pfn_array); 325 - return ret; 362 + return result; 326 363 } 364 + 365 + static bool hv_vtom_tlb_flush_required(bool private) 366 + { 367 + return true; 368 + } 369 + 370 + static bool hv_vtom_cache_flush_required(void) 371 + { 372 + return false; 373 + } 374 + 375 + static bool hv_is_private_mmio(u64 addr) 376 + { 377 + /* 378 + * Hyper-V always provides a single IO-APIC in a guest VM. 379 + * When a paravisor is used, it is emulated by the paravisor 380 + * in the guest context and must be mapped private. 381 + */ 382 + if (addr >= HV_IOAPIC_BASE_ADDRESS && 383 + addr < (HV_IOAPIC_BASE_ADDRESS + PAGE_SIZE)) 384 + return true; 385 + 386 + /* Same with a vTPM */ 387 + if (addr >= VTPM_BASE_ADDRESS && 388 + addr < (VTPM_BASE_ADDRESS + PAGE_SIZE)) 389 + return true; 390 + 391 + return false; 392 + } 393 + 394 + void __init hv_vtom_init(void) 395 + { 396 + /* 397 + * By design, a VM using vTOM doesn't see the SEV setting, 398 + * so SEV initialization is bypassed and sev_status isn't set. 399 + * Set it here to indicate a vTOM VM. 400 + */ 401 + sev_status = MSR_AMD64_SNP_VTOM; 402 + cc_set_vendor(CC_VENDOR_AMD); 403 + cc_set_mask(ms_hyperv.shared_gpa_boundary); 404 + physical_mask &= ms_hyperv.shared_gpa_boundary - 1; 405 + 406 + x86_platform.hyper.is_private_mmio = hv_is_private_mmio; 407 + x86_platform.guest.enc_cache_flush_required = hv_vtom_cache_flush_required; 408 + x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required; 409 + x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility; 410 + } 411 + 412 + #endif /* CONFIG_AMD_MEM_ENCRYPT */ 327 413 328 414 /* 329 415 * hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM. ··· 393 377 pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) + 394 378 (ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT); 395 379 396 - vaddr = vmap_pfn(pfns, size / PAGE_SIZE, PAGE_KERNEL_IO); 380 + vaddr = vmap_pfn(pfns, size / PAGE_SIZE, pgprot_decrypted(PAGE_KERNEL)); 397 381 kfree(pfns); 398 382 399 383 return vaddr; ··· 402 386 void hv_unmap_memory(void *addr) 403 387 { 404 388 vunmap(addr); 389 + } 390 + 391 + enum hv_isolation_type hv_get_isolation_type(void) 392 + { 393 + if (!(ms_hyperv.priv_high & HV_ISOLATION)) 394 + return HV_ISOLATION_TYPE_NONE; 395 + return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); 396 + } 397 + EXPORT_SYMBOL_GPL(hv_get_isolation_type); 398 + 399 + /* 400 + * hv_is_isolation_supported - Check system runs in the Hyper-V 401 + * isolation VM. 402 + */ 403 + bool hv_is_isolation_supported(void) 404 + { 405 + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) 406 + return false; 407 + 408 + if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) 409 + return false; 410 + 411 + return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; 412 + } 413 + 414 + DEFINE_STATIC_KEY_FALSE(isolation_type_snp); 415 + 416 + /* 417 + * hv_isolation_type_snp - Check system runs in the AMD SEV-SNP based 418 + * isolation VM. 419 + */ 420 + bool hv_isolation_type_snp(void) 421 + { 422 + return static_branch_unlikely(&isolation_type_snp); 405 423 }
+20 -4
arch/x86/include/asm/coco.h
··· 7 7 enum cc_vendor { 8 8 CC_VENDOR_NONE, 9 9 CC_VENDOR_AMD, 10 - CC_VENDOR_HYPERV, 11 10 CC_VENDOR_INTEL, 12 11 }; 13 12 14 - void cc_set_vendor(enum cc_vendor v); 15 - void cc_set_mask(u64 mask); 16 - 17 13 #ifdef CONFIG_ARCH_HAS_CC_PLATFORM 14 + extern enum cc_vendor cc_vendor; 15 + 16 + static inline enum cc_vendor cc_get_vendor(void) 17 + { 18 + return cc_vendor; 19 + } 20 + 21 + static inline void cc_set_vendor(enum cc_vendor vendor) 22 + { 23 + cc_vendor = vendor; 24 + } 25 + 26 + void cc_set_mask(u64 mask); 18 27 u64 cc_mkenc(u64 val); 19 28 u64 cc_mkdec(u64 val); 20 29 #else 30 + static inline enum cc_vendor cc_get_vendor(void) 31 + { 32 + return CC_VENDOR_NONE; 33 + } 34 + 35 + static inline void cc_set_vendor(enum cc_vendor vendor) { } 36 + 21 37 static inline u64 cc_mkenc(u64 val) 22 38 { 23 39 return val;
+1
arch/x86/include/asm/mem_encrypt.h
··· 56 56 #else /* !CONFIG_AMD_MEM_ENCRYPT */ 57 57 58 58 #define sme_me_mask 0ULL 59 + #define sev_status 0ULL 59 60 60 61 static inline void __init sme_early_encrypt(resource_size_t paddr, 61 62 unsigned long size) { }
+10 -6
arch/x86/include/asm/mshyperv.h
··· 11 11 #include <asm/paravirt.h> 12 12 #include <asm/mshyperv.h> 13 13 14 + /* 15 + * Hyper-V always provides a single IO-APIC at this MMIO address. 16 + * Ideally, the value should be looked up in ACPI tables, but it 17 + * is needed for mapping the IO-APIC early in boot on Confidential 18 + * VMs, before ACPI functions can be used. 19 + */ 20 + #define HV_IOAPIC_BASE_ADDRESS 0xfec00000 21 + 14 22 union hv_ghcb; 15 23 16 24 DECLARE_STATIC_KEY_FALSE(isolation_type_snp); ··· 214 206 int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, 215 207 struct hv_interrupt_entry *entry); 216 208 int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); 217 - int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible); 218 209 219 210 #ifdef CONFIG_AMD_MEM_ENCRYPT 220 211 void hv_ghcb_msr_write(u64 msr, u64 value); 221 212 void hv_ghcb_msr_read(u64 msr, u64 *value); 222 213 bool hv_ghcb_negotiate_protocol(void); 223 214 void hv_ghcb_terminate(unsigned int set, unsigned int reason); 215 + void hv_vtom_init(void); 224 216 #else 225 217 static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} 226 218 static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {} 227 219 static inline bool hv_ghcb_negotiate_protocol(void) { return false; } 228 220 static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {} 221 + static inline void hv_vtom_init(void) {} 229 222 #endif 230 223 231 224 extern bool hv_isolation_type_snp(void); ··· 268 259 static inline u64 hv_get_register(unsigned int reg) { return 0; } 269 260 static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { } 270 261 static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; } 271 - static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages, 272 - bool visible) 273 - { 274 - return -1; 275 - } 276 262 #endif /* CONFIG_HYPERV */ 277 263 278 264
-4
arch/x86/include/asm/sev-common.h
··· 128 128 struct psc_entry entries[VMGEXIT_PSC_MAX_ENTRY]; 129 129 } __packed; 130 130 131 - /* Guest message request error codes */ 132 - #define SNP_GUEST_REQ_INVALID_LEN BIT_ULL(32) 133 - #define SNP_GUEST_REQ_ERR_BUSY BIT_ULL(33) 134 - 135 131 #define GHCB_MSR_TERM_REQ 0x100 136 132 #define GHCB_MSR_TERM_REASON_SET_POS 12 137 133 #define GHCB_MSR_TERM_REASON_SET_MASK 0xf
+7 -3
arch/x86/include/asm/sev.h
··· 9 9 #define __ASM_ENCRYPTED_STATE_H 10 10 11 11 #include <linux/types.h> 12 + #include <linux/sev-guest.h> 13 + 12 14 #include <asm/insn.h> 13 15 #include <asm/sev-common.h> 14 16 #include <asm/bootparam.h> ··· 187 185 188 186 return rc; 189 187 } 188 + 189 + struct snp_guest_request_ioctl; 190 + 190 191 void setup_ghcb(void); 191 192 void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, 192 193 unsigned int npages); ··· 201 196 void snp_set_wakeup_secondary_cpu(void); 202 197 bool snp_init(struct boot_params *bp); 203 198 void __init __noreturn snp_abort(void); 204 - int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err); 199 + int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio); 205 200 #else 206 201 static inline void sev_es_ist_enter(struct pt_regs *regs) { } 207 202 static inline void sev_es_ist_exit(void) { } ··· 221 216 static inline void snp_set_wakeup_secondary_cpu(void) { } 222 217 static inline bool snp_init(struct boot_params *bp) { return false; } 223 218 static inline void snp_abort(void) { } 224 - static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, 225 - unsigned long *fw_err) 219 + static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) 226 220 { 227 221 return -ENOTTY; 228 222 }
+4
arch/x86/include/asm/x86_init.h
··· 259 259 * VMMCALL under SEV-ES. Needs to return 'false' 260 260 * if the checks fail. Called from the #VC 261 261 * exception handler. 262 + * @is_private_mmio: For CoCo VMs, must map MMIO address as private. 263 + * Used when device is emulated by a paravisor 264 + * layer in the VM context. 262 265 */ 263 266 struct x86_hyper_runtime { 264 267 void (*pin_vcpu)(int cpu); 265 268 void (*sev_es_hcall_prepare)(struct ghcb *ghcb, struct pt_regs *regs); 266 269 bool (*sev_es_hcall_finish)(struct ghcb *ghcb, struct pt_regs *regs); 270 + bool (*is_private_mmio)(u64 addr); 267 271 }; 268 272 269 273 /**
+8 -2
arch/x86/kernel/apic/io_apic.c
··· 66 66 #include <asm/hw_irq.h> 67 67 #include <asm/apic.h> 68 68 #include <asm/pgtable.h> 69 + #include <asm/x86_init.h> 69 70 70 71 #define for_each_ioapic(idx) \ 71 72 for ((idx) = 0; (idx) < nr_ioapics; (idx)++) ··· 2681 2680 pgprot_t flags = FIXMAP_PAGE_NOCACHE; 2682 2681 2683 2682 /* 2684 - * Ensure fixmaps for IOAPIC MMIO respect memory encryption pgprot 2683 + * Ensure fixmaps for IO-APIC MMIO respect memory encryption pgprot 2685 2684 * bits, just like normal ioremap(): 2686 2685 */ 2687 - flags = pgprot_decrypted(flags); 2686 + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { 2687 + if (x86_platform.hyper.is_private_mmio(phys)) 2688 + flags = pgprot_encrypted(flags); 2689 + else 2690 + flags = pgprot_decrypted(flags); 2691 + } 2688 2692 2689 2693 __set_fixmap(idx, phys, flags); 2690 2694 }
+7 -8
arch/x86/kernel/cpu/mshyperv.c
··· 33 33 #include <asm/nmi.h> 34 34 #include <clocksource/hyperv_timer.h> 35 35 #include <asm/numa.h> 36 - #include <asm/coco.h> 37 36 38 37 /* Is Linux running as the root partition? */ 39 38 bool hv_root_partition; ··· 400 401 if (ms_hyperv.priv_high & HV_ISOLATION) { 401 402 ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); 402 403 ms_hyperv.isolation_config_b = cpuid_ebx(HYPERV_CPUID_ISOLATION_CONFIG); 403 - ms_hyperv.shared_gpa_boundary = 404 - BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); 404 + 405 + if (ms_hyperv.shared_gpa_boundary_active) 406 + ms_hyperv.shared_gpa_boundary = 407 + BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); 405 408 406 409 pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", 407 410 ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); ··· 413 412 #ifdef CONFIG_SWIOTLB 414 413 swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary; 415 414 #endif 416 - } 417 - /* Isolation VMs are unenlightened SEV-based VMs, thus this check: */ 418 - if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) { 419 - if (hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE) 420 - cc_set_vendor(CC_VENDOR_HYPERV); 421 415 } 422 416 } 423 417 ··· 482 486 i8253_clear_counter_on_shutdown = false; 483 487 484 488 #if IS_ENABLED(CONFIG_HYPERV) 489 + if ((hv_get_isolation_type() == HV_ISOLATION_TYPE_VBS) || 490 + (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP)) 491 + hv_vtom_init(); 485 492 /* 486 493 * Setup the hook to get control post apic initialization. 487 494 */
+8 -7
arch/x86/kernel/sev.c
··· 22 22 #include <linux/efi.h> 23 23 #include <linux/platform_device.h> 24 24 #include <linux/io.h> 25 + #include <linux/psp-sev.h> 26 + #include <uapi/linux/sev-guest.h> 25 27 26 28 #include <asm/cpu_entry_area.h> 27 29 #include <asm/stacktrace.h> ··· 2177 2175 } 2178 2176 __setup("sev=", init_sev_config); 2179 2177 2180 - int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err) 2178 + int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) 2181 2179 { 2182 2180 struct ghcb_state state; 2183 2181 struct es_em_ctxt ctxt; ··· 2185 2183 struct ghcb *ghcb; 2186 2184 int ret; 2187 2185 2188 - if (!fw_err) 2189 - return -EINVAL; 2186 + rio->exitinfo2 = SEV_RET_NO_FW_CALL; 2190 2187 2191 2188 /* 2192 2189 * __sev_get_ghcb() needs to run with IRQs disabled because it is using ··· 2210 2209 if (ret) 2211 2210 goto e_put; 2212 2211 2213 - *fw_err = ghcb->save.sw_exit_info_2; 2214 - switch (*fw_err) { 2212 + rio->exitinfo2 = ghcb->save.sw_exit_info_2; 2213 + switch (rio->exitinfo2) { 2215 2214 case 0: 2216 2215 break; 2217 2216 2218 - case SNP_GUEST_REQ_ERR_BUSY: 2217 + case SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_BUSY): 2219 2218 ret = -EAGAIN; 2220 2219 break; 2221 2220 2222 - case SNP_GUEST_REQ_INVALID_LEN: 2221 + case SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN): 2223 2222 /* Number of expected pages are returned in RBX */ 2224 2223 if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { 2225 2224 input->data_npages = ghcb_get_rbx(ghcb);
+2
arch/x86/kernel/x86_init.c
··· 134 134 static bool enc_status_change_finish_noop(unsigned long vaddr, int npages, bool enc) { return false; } 135 135 static bool enc_tlb_flush_required_noop(bool enc) { return false; } 136 136 static bool enc_cache_flush_required_noop(void) { return false; } 137 + static bool is_private_mmio_noop(u64 addr) {return false; } 137 138 138 139 struct x86_platform_ops x86_platform __ro_after_init = { 139 140 .calibrate_cpu = native_calibrate_cpu_early, ··· 150 149 .realmode_reserve = reserve_real_mode, 151 150 .realmode_init = init_real_mode, 152 151 .hyper.pin_vcpu = x86_op_int_noop, 152 + .hyper.is_private_mmio = is_private_mmio_noop, 153 153 154 154 .guest = { 155 155 .enc_status_change_prepare = enc_status_change_prepare_noop,
+5
arch/x86/mm/ioremap.c
··· 116 116 if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) 117 117 return; 118 118 119 + if (x86_platform.hyper.is_private_mmio(addr)) { 120 + desc->flags |= IORES_MAP_ENCRYPTED; 121 + return; 122 + } 123 + 119 124 if (!IS_ENABLED(CONFIG_EFI)) 120 125 return; 121 126
+7 -3
arch/x86/mm/mem_encrypt_amd.c
··· 513 513 npages = (vaddr_end - vaddr) >> PAGE_SHIFT; 514 514 515 515 /* 516 - * The unused memory range was mapped decrypted, change the encryption 517 - * attribute from decrypted to encrypted before freeing it. 516 + * If the unused memory range was mapped decrypted, change the encryption 517 + * attribute from decrypted to encrypted before freeing it. Base the 518 + * re-encryption on the same condition used for the decryption in 519 + * sme_postprocess_startup(). Higher level abstractions, such as 520 + * CC_ATTR_MEM_ENCRYPT, aren't necessarily equivalent in a Hyper-V VM 521 + * using vTOM, where sme_me_mask is always zero. 518 522 */ 519 - if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) { 523 + if (sme_me_mask) { 520 524 r = set_memory_encrypted(vaddr, npages); 521 525 if (r) { 522 526 pr_warn("failed to free unused decrypted pages\n");
-3
arch/x86/mm/pat/set_memory.c
··· 2175 2175 2176 2176 static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) 2177 2177 { 2178 - if (hv_is_isolation_supported()) 2179 - return hv_set_mem_host_visibility(addr, numpages, !enc); 2180 - 2181 2178 if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) 2182 2179 return __set_memory_enc_pgtable(addr, numpages, enc); 2183 2180
+14 -8
drivers/crypto/ccp/sev-dev.c
··· 442 442 return __sev_do_cmd_locked(SEV_CMD_INIT_EX, &data, error); 443 443 } 444 444 445 + static inline int __sev_do_init_locked(int *psp_ret) 446 + { 447 + if (sev_init_ex_buffer) 448 + return __sev_init_ex_locked(psp_ret); 449 + else 450 + return __sev_init_locked(psp_ret); 451 + } 452 + 445 453 static int __sev_platform_init_locked(int *error) 446 454 { 455 + int rc = 0, psp_ret = SEV_RET_NO_FW_CALL; 447 456 struct psp_device *psp = psp_master; 448 457 struct sev_device *sev; 449 - int rc = 0, psp_ret = -1; 450 - int (*init_function)(int *error); 451 458 452 459 if (!psp || !psp->sev_data) 453 460 return -ENODEV; ··· 465 458 return 0; 466 459 467 460 if (sev_init_ex_buffer) { 468 - init_function = __sev_init_ex_locked; 469 461 rc = sev_read_init_ex_file(); 470 462 if (rc) 471 463 return rc; 472 - } else { 473 - init_function = __sev_init_locked; 474 464 } 475 465 476 - rc = init_function(&psp_ret); 466 + rc = __sev_do_init_locked(&psp_ret); 477 467 if (rc && psp_ret == SEV_RET_SECURE_DATA_INVALID) { 478 468 /* 479 469 * Initialization command returned an integrity check failure ··· 479 475 * initialization function should succeed by replacing the state 480 476 * with a reset state. 481 477 */ 482 - dev_err(sev->dev, "SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); 483 - rc = init_function(&psp_ret); 478 + dev_err(sev->dev, 479 + "SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); 480 + rc = __sev_do_init_locked(&psp_ret); 484 481 } 482 + 485 483 if (error) 486 484 *error = psp_ret; 487 485
+1 -1
drivers/hv/ring_buffer.c
··· 211 211 212 212 ring_info->ring_buffer = (struct hv_ring_buffer *) 213 213 vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, 214 - PAGE_KERNEL); 214 + pgprot_decrypted(PAGE_KERNEL)); 215 215 kfree(pfns_wraparound); 216 216 217 217 if (!ring_info->ring_buffer)
-1
drivers/hv/vmbus_drv.c
··· 2158 2158 * VMBUS is an acpi enumerated device. Get the information we 2159 2159 * need from DSDT. 2160 2160 */ 2161 - #define VTPM_BASE_ADDRESS 0xfed40000 2162 2161 static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) 2163 2162 { 2164 2163 resource_size_t start = 0;
+62 -37
drivers/virt/coco/sev-guest/sev-guest.c
··· 46 46 47 47 void *certs_data; 48 48 struct snp_guest_crypto *crypto; 49 + /* request and response are in unencrypted memory */ 49 50 struct snp_guest_msg *request, *response; 51 + 52 + /* 53 + * Avoid information leakage by double-buffering shared messages 54 + * in fields that are in regular encrypted memory. 55 + */ 56 + struct snp_guest_msg secret_request, secret_response; 57 + 50 58 struct snp_secrets_page_layout *layout; 51 59 struct snp_req_data input; 52 60 u32 *os_area_msg_seqno; ··· 274 266 static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz) 275 267 { 276 268 struct snp_guest_crypto *crypto = snp_dev->crypto; 277 - struct snp_guest_msg *resp = snp_dev->response; 278 - struct snp_guest_msg *req = snp_dev->request; 269 + struct snp_guest_msg *resp = &snp_dev->secret_response; 270 + struct snp_guest_msg *req = &snp_dev->secret_request; 279 271 struct snp_guest_msg_hdr *req_hdr = &req->hdr; 280 272 struct snp_guest_msg_hdr *resp_hdr = &resp->hdr; 281 273 282 274 dev_dbg(snp_dev->dev, "response [seqno %lld type %d version %d sz %d]\n", 283 275 resp_hdr->msg_seqno, resp_hdr->msg_type, resp_hdr->msg_version, resp_hdr->msg_sz); 276 + 277 + /* Copy response from shared memory to encrypted memory. */ 278 + memcpy(resp, snp_dev->response, sizeof(*resp)); 284 279 285 280 /* Verify that the sequence counter is incremented by 1 */ 286 281 if (unlikely(resp_hdr->msg_seqno != (req_hdr->msg_seqno + 1))) ··· 308 297 static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type, 309 298 void *payload, size_t sz) 310 299 { 311 - struct snp_guest_msg *req = snp_dev->request; 300 + struct snp_guest_msg *req = &snp_dev->secret_request; 312 301 struct snp_guest_msg_hdr *hdr = &req->hdr; 313 302 314 303 memset(req, 0, sizeof(*req)); ··· 332 321 return __enc_payload(snp_dev, req, payload, sz); 333 322 } 334 323 335 - static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, __u64 *fw_err) 324 + static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, 325 + struct snp_guest_request_ioctl *rio) 336 326 { 337 - unsigned long err = 0xff, override_err = 0; 338 327 unsigned long req_start = jiffies; 339 328 unsigned int override_npages = 0; 329 + u64 override_err = 0; 340 330 int rc; 341 331 342 332 retry_request: ··· 347 335 * sequence number must be incremented or the VMPCK must be deleted to 348 336 * prevent reuse of the IV. 349 337 */ 350 - rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err); 338 + rc = snp_issue_guest_request(exit_code, &snp_dev->input, rio); 351 339 switch (rc) { 352 340 case -ENOSPC: 353 341 /* ··· 365 353 * request buffer size was too small and give the caller the 366 354 * required buffer size. 367 355 */ 368 - override_err = SNP_GUEST_REQ_INVALID_LEN; 356 + override_err = SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN); 369 357 370 358 /* 371 359 * If this call to the firmware succeeds, the sequence number can ··· 378 366 goto retry_request; 379 367 380 368 /* 381 - * The host may return SNP_GUEST_REQ_ERR_EBUSY if the request has been 369 + * The host may return SNP_GUEST_VMM_ERR_BUSY if the request has been 382 370 * throttled. Retry in the driver to avoid returning and reusing the 383 371 * message sequence number on a different message. 384 372 */ ··· 399 387 */ 400 388 snp_inc_msg_seqno(snp_dev); 401 389 402 - if (fw_err) 403 - *fw_err = override_err ?: err; 390 + if (override_err) { 391 + rio->exitinfo2 = override_err; 392 + 393 + /* 394 + * If an extended guest request was issued and the supplied certificate 395 + * buffer was not large enough, a standard guest request was issued to 396 + * prevent IV reuse. If the standard request was successful, return -EIO 397 + * back to the caller as would have originally been returned. 398 + */ 399 + if (!rc && override_err == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) 400 + rc = -EIO; 401 + } 404 402 405 403 if (override_npages) 406 404 snp_dev->input.data_npages = override_npages; 407 405 408 - /* 409 - * If an extended guest request was issued and the supplied certificate 410 - * buffer was not large enough, a standard guest request was issued to 411 - * prevent IV reuse. If the standard request was successful, return -EIO 412 - * back to the caller as would have originally been returned. 413 - */ 414 - if (!rc && override_err == SNP_GUEST_REQ_INVALID_LEN) 415 - return -EIO; 416 - 417 406 return rc; 418 407 } 419 408 420 - static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, int msg_ver, 421 - u8 type, void *req_buf, size_t req_sz, void *resp_buf, 422 - u32 resp_sz, __u64 *fw_err) 409 + static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, 410 + struct snp_guest_request_ioctl *rio, u8 type, 411 + void *req_buf, size_t req_sz, void *resp_buf, 412 + u32 resp_sz) 423 413 { 424 414 u64 seqno; 425 415 int rc; ··· 431 417 if (!seqno) 432 418 return -EIO; 433 419 420 + /* Clear shared memory's response for the host to populate. */ 434 421 memset(snp_dev->response, 0, sizeof(struct snp_guest_msg)); 435 422 436 - /* Encrypt the userspace provided payload */ 437 - rc = enc_payload(snp_dev, seqno, msg_ver, type, req_buf, req_sz); 423 + /* Encrypt the userspace provided payload in snp_dev->secret_request. */ 424 + rc = enc_payload(snp_dev, seqno, rio->msg_version, type, req_buf, req_sz); 438 425 if (rc) 439 426 return rc; 440 427 441 - rc = __handle_guest_request(snp_dev, exit_code, fw_err); 428 + /* 429 + * Write the fully encrypted request to the shared unencrypted 430 + * request page. 431 + */ 432 + memcpy(snp_dev->request, &snp_dev->secret_request, 433 + sizeof(snp_dev->secret_request)); 434 + 435 + rc = __handle_guest_request(snp_dev, exit_code, rio); 442 436 if (rc) { 443 - if (rc == -EIO && *fw_err == SNP_GUEST_REQ_INVALID_LEN) 437 + if (rc == -EIO && 438 + rio->exitinfo2 == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) 444 439 return rc; 445 440 446 - dev_alert(snp_dev->dev, "Detected error from ASP request. rc: %d, fw_err: %llu\n", rc, *fw_err); 441 + dev_alert(snp_dev->dev, 442 + "Detected error from ASP request. rc: %d, exitinfo2: 0x%llx\n", 443 + rc, rio->exitinfo2); 444 + 447 445 snp_disable_vmpck(snp_dev); 448 446 return rc; 449 447 } ··· 495 469 if (!resp) 496 470 return -ENOMEM; 497 471 498 - rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, 472 + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, 499 473 SNP_MSG_REPORT_REQ, &req, sizeof(req), resp->data, 500 - resp_len, &arg->fw_err); 474 + resp_len); 501 475 if (rc) 502 476 goto e_free; 503 477 ··· 535 509 if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) 536 510 return -EFAULT; 537 511 538 - rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, 539 - SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len, 540 - &arg->fw_err); 512 + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, 513 + SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len); 541 514 if (rc) 542 515 return rc; 543 516 ··· 596 571 return -ENOMEM; 597 572 598 573 snp_dev->input.data_npages = npages; 599 - ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg->msg_version, 574 + ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg, 600 575 SNP_MSG_REPORT_REQ, &req.data, 601 - sizeof(req.data), resp->data, resp_len, &arg->fw_err); 576 + sizeof(req.data), resp->data, resp_len); 602 577 603 578 /* If certs length is invalid then copy the returned length */ 604 - if (arg->fw_err == SNP_GUEST_REQ_INVALID_LEN) { 579 + if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) { 605 580 req.certs_len = snp_dev->input.data_npages << PAGE_SHIFT; 606 581 607 582 if (copy_to_user((void __user *)arg->req_data, &req, sizeof(req))) ··· 636 611 if (copy_from_user(&input, argp, sizeof(input))) 637 612 return -EFAULT; 638 613 639 - input.fw_err = 0xff; 614 + input.exitinfo2 = 0xff; 640 615 641 616 /* Message version must be non-zero */ 642 617 if (!input.msg_version) ··· 667 642 668 643 mutex_unlock(&snp_cmd_mutex); 669 644 670 - if (input.fw_err && copy_to_user(argp, &input, sizeof(input))) 645 + if (input.exitinfo2 && copy_to_user(argp, &input, sizeof(input))) 671 646 return -EFAULT; 672 647 673 648 return ret;
+2
include/asm-generic/mshyperv.h
··· 26 26 #include <asm/ptrace.h> 27 27 #include <asm/hyperv-tlfs.h> 28 28 29 + #define VTPM_BASE_ADDRESS 0xfed40000 30 + 29 31 struct ms_hyperv_info { 30 32 u32 features; 31 33 u32 priv_high;
+7
include/uapi/linux/psp-sev.h
··· 36 36 * SEV Firmware status code 37 37 */ 38 38 typedef enum { 39 + /* 40 + * This error code is not in the SEV spec. Its purpose is to convey that 41 + * there was an error that prevented the SEV firmware from being called. 42 + * The SEV API error codes are 16 bits, so the -1 value will not overlap 43 + * with possible values from the specification. 44 + */ 45 + SEV_RET_NO_FW_CALL = -1, 39 46 SEV_RET_SUCCESS = 0, 40 47 SEV_RET_INVALID_PLATFORM_STATE, 41 48 SEV_RET_INVALID_GUEST_STATE,
+16 -2
include/uapi/linux/sev-guest.h
··· 52 52 __u64 req_data; 53 53 __u64 resp_data; 54 54 55 - /* firmware error code on failure (see psp-sev.h) */ 56 - __u64 fw_err; 55 + /* bits[63:32]: VMM error code, bits[31:0] firmware error code (see psp-sev.h) */ 56 + union { 57 + __u64 exitinfo2; 58 + struct { 59 + __u32 fw_error; 60 + __u32 vmm_error; 61 + }; 62 + }; 57 63 }; 58 64 59 65 struct snp_ext_report_req { ··· 82 76 83 77 /* Get SNP extended report as defined in the GHCB specification version 2. */ 84 78 #define SNP_GET_EXT_REPORT _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x2, struct snp_guest_request_ioctl) 79 + 80 + /* Guest message request EXIT_INFO_2 constants */ 81 + #define SNP_GUEST_FW_ERR_MASK GENMASK_ULL(31, 0) 82 + #define SNP_GUEST_VMM_ERR_SHIFT 32 83 + #define SNP_GUEST_VMM_ERR(x) (((u64)x) << SNP_GUEST_VMM_ERR_SHIFT) 84 + 85 + #define SNP_GUEST_VMM_ERR_INVALID_LEN 1 86 + #define SNP_GUEST_VMM_ERR_BUSY 2 85 87 86 88 #endif /* __UAPI_LINUX_SEV_GUEST_H_ */
+11 -8
init/main.c
··· 1092 1092 */ 1093 1093 locking_selftest(); 1094 1094 1095 - /* 1096 - * This needs to be called before any devices perform DMA 1097 - * operations that might use the SWIOTLB bounce buffers. It will 1098 - * mark the bounce buffers as decrypted so that their usage will 1099 - * not cause "plain-text" data to be decrypted when accessed. 1100 - */ 1101 - mem_encrypt_init(); 1102 - 1103 1095 #ifdef CONFIG_BLK_DEV_INITRD 1104 1096 if (initrd_start && !initrd_below_start_ok && 1105 1097 page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { ··· 1108 1116 late_time_init(); 1109 1117 sched_clock_init(); 1110 1118 calibrate_delay(); 1119 + 1120 + /* 1121 + * This needs to be called before any devices perform DMA 1122 + * operations that might use the SWIOTLB bounce buffers. It will 1123 + * mark the bounce buffers as decrypted so that their usage will 1124 + * not cause "plain-text" data to be decrypted when accessed. It 1125 + * must be called after late_time_init() so that Hyper-V x86/x64 1126 + * hypercalls work when the SWIOTLB bounce buffers are decrypted. 1127 + */ 1128 + mem_encrypt_init(); 1129 + 1111 1130 pid_idr_init(); 1112 1131 anon_vma_init(); 1113 1132 #ifdef CONFIG_X86