Pull x86 SEV updates from Borislav Petkov: - Add the necessary glue so that the kernel can run as a confidential SEV-SNP vTOM guest on Hyper-V. A vTOM guest basically splits the address space in two parts: encrypted and unencrypted. The use case being running unmodified guests on the Hyper-V confidential computing hypervisor - Double-buffer messages between the guest and the hardware PSP device so that no partial buffers are copied back'n'forth and thus potential message integrity and leak attacks are possible - Name the return value the sev-guest driver returns when the hw PSP device hasn't been called, explicitly - Cleanups * tag 'x86_sev_for_v6.4_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: 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 x86/sev: Change snp_guest_issue_request()'s fw_err argument virt/coco/sev-guest: Double-buffer messages crypto: ccp: Get rid of __sev_platform_init_locked()'s local function pointer crypto: ccp - Name -1 return value as SEV_RET_NO_FW_CALL
Unified · Split
| @@ -37,11 +37,11 @@ along with a description: · 36 unmodified lines | ||
| 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,8 +57,14 @@ counter (e.g. counter overflow), then -EIO will be returned. · 9 unmodified lines | ||
| 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 |
| @@ -29,6 +29,22 @@ static bool intel_cc_platform_has(enum cc_attr attr) · 28 unmodified lines | ||
| 29 | 29 | } |
| 30 | 30 | } |
| 31 | 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) { | |
| 40 | + case CC_ATTR_GUEST_MEM_ENCRYPT: | |
| 41 | + case CC_ATTR_MEM_ENCRYPT: | |
| 42 | + return true; | |
| 43 | + default: | |
| 44 | + return false; | |
| 45 | + } | |
| 46 | +} | |
| 47 | + | |
| 32 | 48 | /* |
| 33 | 49 | * SME and SEV are very similar but they are not the same, so there are |
| 34 | 50 | * times that the kernel will need to distinguish between SME and SEV. The |
| @@ -41,9 +57,14 @@ static bool intel_cc_platform_has(enum cc_attr attr) · 6 unmodified lines | ||
| 41 | 57 | * up under SME the trampoline area cannot be encrypted, whereas under SEV |
| 42 | 58 | * the trampoline area must be encrypted. |
| 43 | 59 | */ |
| 60 | + | |
| 44 | 61 | static bool amd_cc_platform_has(enum cc_attr attr) |
| 45 | 62 | { |
| 46 | 63 | #ifdef CONFIG_AMD_MEM_ENCRYPT |
| 64 | + | |
| 65 | + if (sev_status & MSR_AMD64_SNP_VTOM) | |
| 66 | + return amd_cc_platform_vtom(attr); | |
| 67 | + | |
| 47 | 68 | switch (attr) { |
| 48 | 69 | case CC_ATTR_MEM_ENCRYPT: |
| 49 | 70 | return sme_me_mask; |
| @@ -76,11 +97,6 @@ static bool amd_cc_platform_has(enum cc_attr attr) · 26 unmodified lines | ||
| 76 | 97 | #endif |
| 77 | 98 | } |
| 78 | 99 | |
| 79 | −static bool hyperv_cc_platform_has(enum cc_attr attr) | |
| 80 | −{ | |
| 81 | − return attr == CC_ATTR_GUEST_MEM_ENCRYPT; | |
| 82 | −} | |
| 83 | − | |
| 84 | 100 | bool cc_platform_has(enum cc_attr attr) |
| 85 | 101 | { |
| 86 | 102 | switch (vendor) { |
| @@ -88,8 +104,6 @@ bool cc_platform_has(enum cc_attr attr) · 1 unmodified line | ||
| 88 | 104 | return amd_cc_platform_has(attr); |
| 89 | 105 | case CC_VENDOR_INTEL: |
| 90 | 106 | return intel_cc_platform_has(attr); |
| 91 | − case CC_VENDOR_HYPERV: | |
| 92 | − return hyperv_cc_platform_has(attr); | |
| 93 | 107 | default: |
| 94 | 108 | return false; |
| 95 | 109 | } |
| @@ -103,11 +117,14 @@ u64 cc_mkenc(u64 val) · 7 unmodified lines | ||
| 103 | 117 | * encryption status of the page. |
| 104 | 118 | * |
| 105 | 119 | * - for AMD, bit *set* means the page is encrypted |
| 106 | − * - for Intel *clear* means encrypted. | |
| 120 | + * - for AMD with vTOM and for Intel, *clear* means encrypted | |
| 107 | 121 | */ |
| 108 | 122 | switch (vendor) { |
| 109 | 123 | case CC_VENDOR_AMD: |
| 110 | − return val | cc_mask; | |
| 124 | + if (sev_status & MSR_AMD64_SNP_VTOM) | |
| 125 | + return val & ~cc_mask; | |
| 126 | + else | |
| 127 | + return val | cc_mask; | |
| 111 | 128 | case CC_VENDOR_INTEL: |
| 112 | 129 | return val & ~cc_mask; |
| 113 | 130 | default: |
| @@ -120,7 +137,10 @@ u64 cc_mkdec(u64 val) · 6 unmodified lines | ||
| 120 | 137 | /* See comment in cc_mkenc() */ |
| 121 | 138 | switch (vendor) { |
| 122 | 139 | case CC_VENDOR_AMD: |
| 123 | − return val & ~cc_mask; | |
| 140 | + if (sev_status & MSR_AMD64_SNP_VTOM) | |
| 141 | + return val | cc_mask; | |
| 142 | + else | |
| 143 | + return val & ~cc_mask; | |
| 124 | 144 | case CC_VENDOR_INTEL: |
| 125 | 145 | return val | cc_mask; |
| 126 | 146 | default: |
| @@ -29,7 +29,6 @@ · 28 unmodified lines | ||
| 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; |
| @@ -504,16 +503,6 @@ void __init hyperv_init(void) · 468 unmodified lines | ||
| 504 | 503 | /* Query the VMs extended capability once, so that it can be cached. */ |
| 505 | 504 | hv_query_ext_cap(0); |
| 506 | 505 | |
| 507 | −#ifdef CONFIG_SWIOTLB | |
| 508 | − /* | |
| 509 | − * Swiotlb bounce buffer needs to be mapped in extra address | |
| 510 | − * space. Map function doesn't work in the early place and so | |
| 511 | − * call swiotlb_update_mem_attributes() here. | |
| 512 | − */ | |
| 513 | − if (hv_is_isolation_supported()) | |
| 514 | − swiotlb_update_mem_attributes(); | |
| 515 | −#endif | |
| 516 | − | |
| 517 | 506 | return; |
| 518 | 507 | |
| 519 | 508 | clean_guest_os_id: |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | ||
| 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 | |
| @@ -233,41 +235,6 @@ void hv_ghcb_msr_read(u64 msr, u64 *value) · 214 unmodified lines | ||
| 233 | 235 | local_irq_restore(flags); |
| 234 | 236 | } |
| 235 | 237 | EXPORT_SYMBOL_GPL(hv_ghcb_msr_read); |
| 236 | −#endif | |
| 237 | − | |
| 238 | −enum hv_isolation_type hv_get_isolation_type(void) | |
| 239 | −{ | |
| 240 | − if (!(ms_hyperv.priv_high & HV_ISOLATION)) | |
| 241 | − return HV_ISOLATION_TYPE_NONE; | |
| 242 | − return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); | |
| 243 | −} | |
| 244 | −EXPORT_SYMBOL_GPL(hv_get_isolation_type); | |
| 245 | − | |
| 246 | −/* | |
| 247 | − * hv_is_isolation_supported - Check system runs in the Hyper-V | |
| 248 | − * isolation VM. | |
| 249 | − */ | |
| 250 | −bool hv_is_isolation_supported(void) | |
| 251 | −{ | |
| 252 | − if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) | |
| 253 | − return false; | |
| 254 | − | |
| 255 | − if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) | |
| 256 | − return false; | |
| 257 | − | |
| 258 | − return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; | |
| 259 | −} | |
| 260 | − | |
| 261 | −DEFINE_STATIC_KEY_FALSE(isolation_type_snp); | |
| 262 | − | |
| 263 | −/* | |
| 264 | − * hv_isolation_type_snp - Check system runs in the AMD SEV-SNP based | |
| 265 | − * isolation VM. | |
| 266 | − */ | |
| 267 | −bool hv_isolation_type_snp(void) | |
| 268 | −{ | |
| 269 | − return static_branch_unlikely(&isolation_type_snp); | |
| 270 | −} | |
| 271 | 238 | |
| 272 | 239 | /* |
| 273 | 240 | * hv_mark_gpa_visibility - Set pages visible to host via hvcall. |
| @@ -320,27 +287,25 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[], · 46 unmodified lines | ||
| 320 | 287 | } |
| 321 | 288 | |
| 322 | 289 | /* |
| 323 | − * hv_set_mem_host_visibility - Set specified memory visible to host. | |
| 290 | + * hv_vtom_set_host_visibility - Set specified memory visible to host. | |
| 324 | 291 | * |
| 325 | 292 | * In Isolation VM, all guest memory is encrypted from host and guest |
| 326 | 293 | * needs to set memory visible to host via hvcall before sharing memory |
| 327 | 294 | * with host. This function works as wrap of hv_mark_gpa_visibility() |
| 328 | 295 | * with memory base and size. |
| 329 | 296 | */ |
| 330 | −int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visible) | |
| 297 | +static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bool enc) | |
| 331 | 298 | { |
| 332 | − enum hv_mem_host_visibility visibility = visible ? | |
| 333 | − VMBUS_PAGE_VISIBLE_READ_WRITE : VMBUS_PAGE_NOT_VISIBLE; | |
| 299 | + enum hv_mem_host_visibility visibility = enc ? | |
| 300 | + VMBUS_PAGE_NOT_VISIBLE : VMBUS_PAGE_VISIBLE_READ_WRITE; | |
| 334 | 301 | u64 *pfn_array; |
| 335 | 302 | int ret = 0; |
| 303 | + bool result = true; | |
| 336 | 304 | int i, pfn; |
| 337 | 305 | |
| 338 | − if (!hv_is_isolation_supported() || !hv_hypercall_pg) | |
| 339 | − return 0; | |
| 340 | − | |
| 341 | 306 | pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); |
| 342 | 307 | if (!pfn_array) |
| 343 | − return -ENOMEM; | |
| 308 | + return false; | |
| 344 | 309 | |
| 345 | 310 | for (i = 0, pfn = 0; i < pagecount; i++) { |
| 346 | 311 | pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE); |
| @@ -349,17 +314,68 @@ int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visibl · 2 unmodified lines | ||
| 349 | 314 | if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) { |
| 350 | 315 | ret = hv_mark_gpa_visibility(pfn, pfn_array, |
| 351 | 316 | visibility); |
| 352 | − if (ret) | |
| 317 | + if (ret) { | |
| 318 | + result = false; | |
| 353 | 319 | goto err_free_pfn_array; |
| 320 | + } | |
| 354 | 321 | pfn = 0; |
| 355 | 322 | } |
| 356 | 323 | } |
| 357 | 324 | |
| 358 | 325 | err_free_pfn_array: |
| 359 | 326 | kfree(pfn_array); |
| 360 | − return ret; | |
| 327 | + return result; | |
| 328 | +} | |
| 329 | + | |
| 330 | +static bool hv_vtom_tlb_flush_required(bool private) | |
| 331 | +{ | |
| 332 | + return true; | |
| 361 | 333 | } |
| 362 | 334 | |
| 335 | +static bool hv_vtom_cache_flush_required(void) | |
| 336 | +{ | |
| 337 | + return false; | |
| 338 | +} | |
| 339 | + | |
| 340 | +static bool hv_is_private_mmio(u64 addr) | |
| 341 | +{ | |
| 342 | + /* | |
| 343 | + * Hyper-V always provides a single IO-APIC in a guest VM. | |
| 344 | + * When a paravisor is used, it is emulated by the paravisor | |
| 345 | + * in the guest context and must be mapped private. | |
| 346 | + */ | |
| 347 | + if (addr >= HV_IOAPIC_BASE_ADDRESS && | |
| 348 | + addr < (HV_IOAPIC_BASE_ADDRESS + PAGE_SIZE)) | |
| 349 | + return true; | |
| 350 | + | |
| 351 | + /* Same with a vTPM */ | |
| 352 | + if (addr >= VTPM_BASE_ADDRESS && | |
| 353 | + addr < (VTPM_BASE_ADDRESS + PAGE_SIZE)) | |
| 354 | + return true; | |
| 355 | + | |
| 356 | + return false; | |
| 357 | +} | |
| 358 | + | |
| 359 | +void __init hv_vtom_init(void) | |
| 360 | +{ | |
| 361 | + /* | |
| 362 | + * By design, a VM using vTOM doesn't see the SEV setting, | |
| 363 | + * so SEV initialization is bypassed and sev_status isn't set. | |
| 364 | + * Set it here to indicate a vTOM VM. | |
| 365 | + */ | |
| 366 | + sev_status = MSR_AMD64_SNP_VTOM; | |
| 367 | + cc_set_vendor(CC_VENDOR_AMD); | |
| 368 | + cc_set_mask(ms_hyperv.shared_gpa_boundary); | |
| 369 | + physical_mask &= ms_hyperv.shared_gpa_boundary - 1; | |
| 370 | + | |
| 371 | + x86_platform.hyper.is_private_mmio = hv_is_private_mmio; | |
| 372 | + x86_platform.guest.enc_cache_flush_required = hv_vtom_cache_flush_required; | |
| 373 | + x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required; | |
| 374 | + x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility; | |
| 375 | +} | |
| 376 | + | |
| 377 | +#endif /* CONFIG_AMD_MEM_ENCRYPT */ | |
| 378 | + | |
| 363 | 379 | /* |
| 364 | 380 | * hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM. |
| 365 | 381 | */ |
| @@ -377,7 +393,7 @@ void *hv_map_memory(void *addr, unsigned long size) · 11 unmodified lines | ||
| 377 | 393 | pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) + |
| 378 | 394 | (ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT); |
| 379 | 395 | |
| 380 | − vaddr = vmap_pfn(pfns, size / PAGE_SIZE, PAGE_KERNEL_IO); | |
| 396 | + vaddr = vmap_pfn(pfns, size / PAGE_SIZE, pgprot_decrypted(PAGE_KERNEL)); | |
| 381 | 397 | kfree(pfns); |
| 382 | 398 | |
| 383 | 399 | return vaddr; |
| @@ -387,3 +403,37 @@ void hv_unmap_memory(void *addr) · 3 unmodified lines | ||
| 387 | 403 | { |
| 388 | 404 | vunmap(addr); |
| 389 | 405 | } |
| 406 | + | |
| 407 | +enum hv_isolation_type hv_get_isolation_type(void) | |
| 408 | +{ | |
| 409 | + if (!(ms_hyperv.priv_high & HV_ISOLATION)) | |
| 410 | + return HV_ISOLATION_TYPE_NONE; | |
| 411 | + return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); | |
| 412 | +} | |
| 413 | +EXPORT_SYMBOL_GPL(hv_get_isolation_type); | |
| 414 | + | |
| 415 | +/* | |
| 416 | + * hv_is_isolation_supported - Check system runs in the Hyper-V | |
| 417 | + * isolation VM. | |
| 418 | + */ | |
| 419 | +bool hv_is_isolation_supported(void) | |
| 420 | +{ | |
| 421 | + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) | |
| 422 | + return false; | |
| 423 | + | |
| 424 | + if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) | |
| 425 | + return false; | |
| 426 | + | |
| 427 | + return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; | |
| 428 | +} | |
| 429 | + | |
| 430 | +DEFINE_STATIC_KEY_FALSE(isolation_type_snp); | |
| 431 | + | |
| 432 | +/* | |
| 433 | + * hv_isolation_type_snp - Check system runs in the AMD SEV-SNP based | |
| 434 | + * isolation VM. | |
| 435 | + */ | |
| 436 | +bool hv_isolation_type_snp(void) | |
| 437 | +{ | |
| 438 | + return static_branch_unlikely(&isolation_type_snp); | |
| 439 | +} | |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | ||
| 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 | |
| @@ -56,6 +56,7 @@ void __init sev_es_init_vc_handling(void); · 55 unmodified lines | ||
| 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) { } |
| @@ -11,6 +11,14 @@ · 10 unmodified lines | ||
| 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); |
| @@ -206,18 +214,19 @@ struct irq_domain *hv_create_pci_msi_domain(void); · 189 unmodified lines | ||
| 206 | 214 | int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, |
| 207 | 215 | struct hv_interrupt_entry *entry); |
| 208 | 216 | int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); |
| 209 | −int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible); | |
| 210 | 217 | |
| 211 | 218 | #ifdef CONFIG_AMD_MEM_ENCRYPT |
| 212 | 219 | void hv_ghcb_msr_write(u64 msr, u64 value); |
| 213 | 220 | void hv_ghcb_msr_read(u64 msr, u64 *value); |
| 214 | 221 | bool hv_ghcb_negotiate_protocol(void); |
| 215 | 222 | void hv_ghcb_terminate(unsigned int set, unsigned int reason); |
| 223 | +void hv_vtom_init(void); | |
| 216 | 224 | #else |
| 217 | 225 | static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} |
| 218 | 226 | static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {} |
| 219 | 227 | static inline bool hv_ghcb_negotiate_protocol(void) { return false; } |
| 220 | 228 | static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {} |
| 229 | +static inline void hv_vtom_init(void) {} | |
| 221 | 230 | #endif |
| 222 | 231 | |
| 223 | 232 | extern bool hv_isolation_type_snp(void); |
| @@ -259,11 +268,6 @@ static inline void hv_set_register(unsigned int reg, u64 value) { } · 35 unmodified lines | ||
| 259 | 268 | static inline u64 hv_get_register(unsigned int reg) { return 0; } |
| 260 | 269 | static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { } |
| 261 | 270 | static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; } |
| 262 | −static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages, | |
| 263 | − bool visible) | |
| 264 | −{ | |
| 265 | − return -1; | |
| 266 | −} | |
| 267 | 271 | #endif /* CONFIG_HYPERV */ |
| 268 | 272 | |
| 269 | 273 | |
| @@ -128,10 +128,6 @@ struct snp_psc_desc { · 127 unmodified lines | ||
| 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 |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | ||
| 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> |
| @@ -185,6 +187,9 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) · 170 unmodified lines | ||
| 185 | 187 | |
| 186 | 188 | return rc; |
| 187 | 189 | } |
| 190 | + | |
| 191 | +struct snp_guest_request_ioctl; | |
| 192 | + | |
| 188 | 193 | void setup_ghcb(void); |
| 189 | 194 | void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, |
| 190 | 195 | unsigned int npages); |
| @@ -196,7 +201,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned int npages); · 5 unmodified lines | ||
| 196 | 201 | void snp_set_wakeup_secondary_cpu(void); |
| 197 | 202 | bool snp_init(struct boot_params *bp); |
| 198 | 203 | void __init __noreturn snp_abort(void); |
| 199 | −int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err); | |
| 204 | +int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio); | |
| 200 | 205 | #else |
| 201 | 206 | static inline void sev_es_ist_enter(struct pt_regs *regs) { } |
| 202 | 207 | static inline void sev_es_ist_exit(void) { } |
| @@ -216,8 +221,7 @@ static inline void snp_set_memory_private(unsigned long vaddr, unsigned int npag · 13 unmodified lines | ||
| 216 | 221 | static inline void snp_set_wakeup_secondary_cpu(void) { } |
| 217 | 222 | static inline bool snp_init(struct boot_params *bp) { return false; } |
| 218 | 223 | static inline void snp_abort(void) { } |
| 219 | −static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, | |
| 220 | − unsigned long *fw_err) | |
| 224 | +static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) | |
| 221 | 225 | { |
| 222 | 226 | return -ENOTTY; |
| 223 | 227 | } |
| @@ -259,11 +259,15 @@ struct x86_legacy_features { · 258 unmodified lines | ||
| 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 | /** |
| @@ -66,6 +66,7 @@ · 65 unmodified lines | ||
| 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)++) |
| @@ -2680,10 +2681,15 @@ static void io_apic_set_fixmap(enum fixed_addresses idx, phys_addr_t phys) · 2608 unmodified lines | ||
| 2680 | 2681 | pgprot_t flags = FIXMAP_PAGE_NOCACHE; |
| 2681 | 2682 | |
| 2682 | 2683 | /* |
| 2683 | − * Ensure fixmaps for IOAPIC MMIO respect memory encryption pgprot | |
| 2684 | + * Ensure fixmaps for IO-APIC MMIO respect memory encryption pgprot | |
| 2684 | 2685 | * bits, just like normal ioremap(): |
| 2685 | 2686 | */ |
| 2686 | − flags = pgprot_decrypted(flags); | |
| 2687 | + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { | |
| 2688 | + if (x86_platform.hyper.is_private_mmio(phys)) | |
| 2689 | + flags = pgprot_encrypted(flags); | |
| 2690 | + else | |
| 2691 | + flags = pgprot_decrypted(flags); | |
| 2692 | + } | |
| 2687 | 2693 | |
| 2688 | 2694 | __set_fixmap(idx, phys, flags); |
| 2689 | 2695 | } |
| @@ -33,7 +33,6 @@ · 32 unmodified lines | ||
| 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; |
| @@ -401,8 +400,10 @@ static void __init ms_hyperv_init_platform(void) · 361 unmodified lines | ||
| 401 | 400 | if (ms_hyperv.priv_high & HV_ISOLATION) { |
| 402 | 401 | ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); |
| 403 | 402 | ms_hyperv.isolation_config_b = cpuid_ebx(HYPERV_CPUID_ISOLATION_CONFIG); |
| 404 | − ms_hyperv.shared_gpa_boundary = | |
| 405 | − BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); | |
| 403 | + | |
| 404 | + if (ms_hyperv.shared_gpa_boundary_active) | |
| 405 | + ms_hyperv.shared_gpa_boundary = | |
| 406 | + BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); | |
| 406 | 407 | |
| 407 | 408 | pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", |
| 408 | 409 | ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); |
| @@ -413,11 +414,6 @@ static void __init ms_hyperv_init_platform(void) · 4 unmodified lines | ||
| 413 | 414 | swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary; |
| 414 | 415 | #endif |
| 415 | 416 | } |
| 416 | − /* Isolation VMs are unenlightened SEV-based VMs, thus this check: */ | |
| 417 | − if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) { | |
| 418 | − if (hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE) | |
| 419 | − cc_set_vendor(CC_VENDOR_HYPERV); | |
| 420 | − } | |
| 421 | 417 | } |
| 422 | 418 | |
| 423 | 419 | if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { |
| @@ -486,6 +482,9 @@ static void __init ms_hyperv_init_platform(void) · 62 unmodified lines | ||
| 486 | 482 | i8253_clear_counter_on_shutdown = false; |
| 487 | 483 | |
| 488 | 484 | #if IS_ENABLED(CONFIG_HYPERV) |
| 485 | + if ((hv_get_isolation_type() == HV_ISOLATION_TYPE_VBS) || | |
| 486 | + (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP)) | |
| 487 | + hv_vtom_init(); | |
| 489 | 488 | /* |
| 490 | 489 | * Setup the hook to get control post apic initialization. |
| 491 | 490 | */ |
| @@ -22,6 +22,8 @@ · 21 unmodified lines | ||
| 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> |
| @@ -2175,7 +2177,7 @@ static int __init init_sev_config(char *str) · 2147 unmodified lines | ||
| 2175 | 2177 | } |
| 2176 | 2178 | __setup("sev=", init_sev_config); |
| 2177 | 2179 | |
| 2178 | −int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err) | |
| 2180 | +int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) | |
| 2179 | 2181 | { |
| 2180 | 2182 | struct ghcb_state state; |
| 2181 | 2183 | struct es_em_ctxt ctxt; |
| @@ -2183,8 +2185,7 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned · 1 unmodified line | ||
| 2183 | 2185 | struct ghcb *ghcb; |
| 2184 | 2186 | int ret; |
| 2185 | 2187 | |
| 2186 | − if (!fw_err) | |
| 2187 | − return -EINVAL; | |
| 2188 | + rio->exitinfo2 = SEV_RET_NO_FW_CALL; | |
| 2188 | 2189 | |
| 2189 | 2190 | /* |
| 2190 | 2191 | * __sev_get_ghcb() needs to run with IRQs disabled because it is using |
| @@ -2209,16 +2210,16 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned · 18 unmodified lines | ||
| 2209 | 2210 | if (ret) |
| 2210 | 2211 | goto e_put; |
| 2211 | 2212 | |
| 2212 | − *fw_err = ghcb->save.sw_exit_info_2; | |
| 2213 | − switch (*fw_err) { | |
| 2213 | + rio->exitinfo2 = ghcb->save.sw_exit_info_2; | |
| 2214 | + switch (rio->exitinfo2) { | |
| 2214 | 2215 | case 0: |
| 2215 | 2216 | break; |
| 2216 | 2217 | |
| 2217 | − case SNP_GUEST_REQ_ERR_BUSY: | |
| 2218 | + case SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_BUSY): | |
| 2218 | 2219 | ret = -EAGAIN; |
| 2219 | 2220 | break; |
| 2220 | 2221 | |
| 2221 | − case SNP_GUEST_REQ_INVALID_LEN: | |
| 2222 | + case SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN): | |
| 2222 | 2223 | /* Number of expected pages are returned in RBX */ |
| 2223 | 2224 | if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { |
| 2224 | 2225 | input->data_npages = ghcb_get_rbx(ghcb); |
| @@ -134,6 +134,7 @@ static void enc_status_change_prepare_noop(unsigned long vaddr, int npages, bool · 133 unmodified lines | ||
| 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, |
| @@ -149,6 +150,7 @@ struct x86_platform_ops x86_platform __ro_after_init = { · 9 unmodified lines | ||
| 149 | 150 | .realmode_reserve = reserve_real_mode, |
| 150 | 151 | .realmode_init = init_real_mode, |
| 151 | 152 | .hyper.pin_vcpu = x86_op_int_noop, |
| 153 | + .hyper.is_private_mmio = is_private_mmio_noop, | |
| 152 | 154 | |
| 153 | 155 | .guest = { |
| 154 | 156 | .enc_status_change_prepare = enc_status_change_prepare_noop, |
| @@ -116,6 +116,11 @@ static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *des · 115 unmodified lines | ||
| 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 | |
| @@ -513,10 +513,14 @@ void __init mem_encrypt_free_decrypted_mem(void) · 512 unmodified lines | ||
| 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"); |
| @@ -2175,9 +2175,6 @@ static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc) · 2174 unmodified lines | ||
| 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 | |
| @@ -442,12 +442,19 @@ static int __sev_init_ex_locked(int *error) · 441 unmodified lines | ||
| 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; |
| @@ -458,15 +465,12 @@ static int __sev_platform_init_locked(int *error) · 4 unmodified lines | ||
| 458 | 465 | return 0; |
| 459 | 466 | |
| 460 | 467 | if (sev_init_ex_buffer) { |
| 461 | − init_function = __sev_init_ex_locked; | |
| 462 | 468 | rc = sev_read_init_ex_file(); |
| 463 | 469 | if (rc) |
| 464 | 470 | return rc; |
| 465 | − } else { | |
| 466 | − init_function = __sev_init_locked; | |
| 467 | 471 | } |
| 468 | 472 | |
| 469 | − rc = init_function(&psp_ret); | |
| 473 | + rc = __sev_do_init_locked(&psp_ret); | |
| 470 | 474 | if (rc && psp_ret == SEV_RET_SECURE_DATA_INVALID) { |
| 471 | 475 | /* |
| 472 | 476 | * Initialization command returned an integrity check failure |
| @@ -475,9 +479,11 @@ static int __sev_platform_init_locked(int *error) · 2 unmodified lines | ||
| 475 | 479 | * initialization function should succeed by replacing the state |
| 476 | 480 | * with a reset state. |
| 477 | 481 | */ |
| 478 | − dev_err(sev->dev, "SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); | |
| 479 | − rc = init_function(&psp_ret); | |
| 482 | + dev_err(sev->dev, | |
| 483 | +"SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); | |
| 484 | + rc = __sev_do_init_locked(&psp_ret); | |
| 480 | 485 | } |
| 486 | + | |
| 481 | 487 | if (error) |
| 482 | 488 | *error = psp_ret; |
| 483 | 489 | |
| @@ -211,7 +211,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, · 210 unmodified lines | ||
| 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) |
| @@ -2156,7 +2156,6 @@ void vmbus_device_unregister(struct hv_device *device_obj) · 2155 unmodified lines | ||
| 2156 | 2156 | * VMBUS is an acpi enumerated device. Get the information we |
| 2157 | 2157 | * need from DSDT. |
| 2158 | 2158 | */ |
| 2159 | −#define VTPM_BASE_ADDRESS 0xfed40000 | |
| 2160 | 2159 | static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) |
| 2161 | 2160 | { |
| 2162 | 2161 | resource_size_t start = 0; |
| @@ -46,7 +46,15 @@ struct snp_guest_dev { · 45 unmodified lines | ||
| 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; |
| @@ -266,14 +274,17 @@ static int dec_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg, · 213 unmodified lines | ||
| 266 | 274 | static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz) |
| 267 | 275 | { |
| 268 | 276 | struct snp_guest_crypto *crypto = snp_dev->crypto; |
| 269 | − struct snp_guest_msg *resp = snp_dev->response; | |
| 270 | − struct snp_guest_msg *req = snp_dev->request; | |
| 277 | + struct snp_guest_msg *resp = &snp_dev->secret_response; | |
| 278 | + struct snp_guest_msg *req = &snp_dev->secret_request; | |
| 271 | 279 | struct snp_guest_msg_hdr *req_hdr = &req->hdr; |
| 272 | 280 | struct snp_guest_msg_hdr *resp_hdr = &resp->hdr; |
| 273 | 281 | |
| 274 | 282 | dev_dbg(snp_dev->dev, "response [seqno %lld type %d version %d sz %d]\n", |
| 275 | 283 | resp_hdr->msg_seqno, resp_hdr->msg_type, resp_hdr->msg_version, resp_hdr->msg_sz); |
| 276 | 284 | |
| 285 | + /* Copy response from shared memory to encrypted memory. */ | |
| 286 | + memcpy(resp, snp_dev->response, sizeof(*resp)); | |
| 287 | + | |
| 277 | 288 | /* Verify that the sequence counter is incremented by 1 */ |
| 278 | 289 | if (unlikely(resp_hdr->msg_seqno != (req_hdr->msg_seqno + 1))) |
| 279 | 290 | return -EBADMSG; |
| @@ -297,7 +308,7 @@ static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, · 17 unmodified lines | ||
| 297 | 308 | static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type, |
| 298 | 309 | void *payload, size_t sz) |
| 299 | 310 | { |
| 300 | − struct snp_guest_msg *req = snp_dev->request; | |
| 311 | + struct snp_guest_msg *req = &snp_dev->secret_request; | |
| 301 | 312 | struct snp_guest_msg_hdr *hdr = &req->hdr; |
| 302 | 313 | |
| 303 | 314 | memset(req, 0, sizeof(*req)); |
| @@ -321,11 +332,12 @@ static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 · 17 unmodified lines | ||
| 321 | 332 | return __enc_payload(snp_dev, req, payload, sz); |
| 322 | 333 | } |
| 323 | 334 | |
| 324 | −static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, __u64 *fw_err) | |
| 335 | +static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, | |
| 336 | + struct snp_guest_request_ioctl *rio) | |
| 325 | 337 | { |
| 326 | − unsigned long err = 0xff, override_err = 0; | |
| 327 | 338 | unsigned long req_start = jiffies; |
| 328 | 339 | unsigned int override_npages = 0; |
| 340 | + u64 override_err = 0; | |
| 329 | 341 | int rc; |
| 330 | 342 | |
| 331 | 343 | retry_request: |
| @@ -335,7 +347,7 @@ retry_request: · 3 unmodified lines | ||
| 335 | 347 | * sequence number must be incremented or the VMPCK must be deleted to |
| 336 | 348 | * prevent reuse of the IV. |
| 337 | 349 | */ |
| 338 | − rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err); | |
| 350 | + rc = snp_issue_guest_request(exit_code, &snp_dev->input, rio); | |
| 339 | 351 | switch (rc) { |
| 340 | 352 | case -ENOSPC: |
| 341 | 353 | /* |
| @@ -353,7 +365,7 @@ retry_request: · 11 unmodified lines | ||
| 353 | 365 | * request buffer size was too small and give the caller the |
| 354 | 366 | * required buffer size. |
| 355 | 367 | */ |
| 356 | − override_err = SNP_GUEST_REQ_INVALID_LEN; | |
| 368 | + override_err = SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN); | |
| 357 | 369 | |
| 358 | 370 | /* |
| 359 | 371 | * If this call to the firmware succeeds, the sequence number can |
| @@ -366,7 +378,7 @@ retry_request: · 6 unmodified lines | ||
| 366 | 378 | goto retry_request; |
| 367 | 379 | |
| 368 | 380 | /* |
| 369 | − * The host may return SNP_GUEST_REQ_ERR_EBUSY if the request has been | |
| 381 | + * The host may return SNP_GUEST_VMM_ERR_BUSY if the request has been | |
| 370 | 382 | * throttled. Retry in the driver to avoid returning and reusing the |
| 371 | 383 | * message sequence number on a different message. |
| 372 | 384 | */ |
| @@ -387,27 +399,29 @@ retry_request: · 14 unmodified lines | ||
| 387 | 399 | */ |
| 388 | 400 | snp_inc_msg_seqno(snp_dev); |
| 389 | 401 | |
| 390 | − if (fw_err) | |
| 391 | − *fw_err = override_err ?: err; | |
| 402 | + if (override_err) { | |
| 403 | + rio->exitinfo2 = override_err; | |
| 404 | + | |
| 405 | + /* | |
| 406 | + * If an extended guest request was issued and the supplied certificate | |
| 407 | + * buffer was not large enough, a standard guest request was issued to | |
| 408 | + * prevent IV reuse. If the standard request was successful, return -EIO | |
| 409 | + * back to the caller as would have originally been returned. | |
| 410 | + */ | |
| 411 | + if (!rc && override_err == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) | |
| 412 | + rc = -EIO; | |
| 413 | + } | |
| 392 | 414 | |
| 393 | 415 | if (override_npages) |
| 394 | 416 | snp_dev->input.data_npages = override_npages; |
| 395 | 417 | |
| 396 | − /* | |
| 397 | − * If an extended guest request was issued and the supplied certificate | |
| 398 | − * buffer was not large enough, a standard guest request was issued to | |
| 399 | − * prevent IV reuse. If the standard request was successful, return -EIO | |
| 400 | − * back to the caller as would have originally been returned. | |
| 401 | − */ | |
| 402 | − if (!rc && override_err == SNP_GUEST_REQ_INVALID_LEN) | |
| 403 | − return -EIO; | |
| 404 | − | |
| 405 | 418 | return rc; |
| 406 | 419 | } |
| 407 | 420 | |
| 408 | −static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, int msg_ver, | |
| 409 | − u8 type, void *req_buf, size_t req_sz, void *resp_buf, | |
| 410 | − u32 resp_sz, __u64 *fw_err) | |
| 421 | +static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, | |
| 422 | + struct snp_guest_request_ioctl *rio, u8 type, | |
| 423 | + void *req_buf, size_t req_sz, void *resp_buf, | |
| 424 | + u32 resp_sz) | |
| 411 | 425 | { |
| 412 | 426 | u64 seqno; |
| 413 | 427 | int rc; |
| @@ -417,19 +431,31 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in · 3 unmodified lines | ||
| 417 | 431 | if (!seqno) |
| 418 | 432 | return -EIO; |
| 419 | 433 | |
| 434 | + /* Clear shared memory's response for the host to populate. */ | |
| 420 | 435 | memset(snp_dev->response, 0, sizeof(struct snp_guest_msg)); |
| 421 | 436 | |
| 422 | − /* Encrypt the userspace provided payload */ | |
| 423 | − rc = enc_payload(snp_dev, seqno, msg_ver, type, req_buf, req_sz); | |
| 437 | + /* Encrypt the userspace provided payload in snp_dev->secret_request. */ | |
| 438 | + rc = enc_payload(snp_dev, seqno, rio->msg_version, type, req_buf, req_sz); | |
| 424 | 439 | if (rc) |
| 425 | 440 | return rc; |
| 426 | 441 | |
| 427 | − rc = __handle_guest_request(snp_dev, exit_code, fw_err); | |
| 442 | + /* | |
| 443 | + * Write the fully encrypted request to the shared unencrypted | |
| 444 | + * request page. | |
| 445 | + */ | |
| 446 | + memcpy(snp_dev->request, &snp_dev->secret_request, | |
| 447 | + sizeof(snp_dev->secret_request)); | |
| 448 | + | |
| 449 | + rc = __handle_guest_request(snp_dev, exit_code, rio); | |
| 428 | 450 | if (rc) { |
| 429 | − if (rc == -EIO && *fw_err == SNP_GUEST_REQ_INVALID_LEN) | |
| 451 | + if (rc == -EIO && | |
| 452 | + rio->exitinfo2 == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) | |
| 430 | 453 | return rc; |
| 431 | 454 | |
| 432 | − dev_alert(snp_dev->dev, "Detected error from ASP request. rc: %d, fw_err: %llu\n", rc, *fw_err); | |
| 455 | + dev_alert(snp_dev->dev, | |
| 456 | + "Detected error from ASP request. rc: %d, exitinfo2: 0x%llx\n", | |
| 457 | + rc, rio->exitinfo2); | |
| 458 | + | |
| 433 | 459 | snp_disable_vmpck(snp_dev); |
| 434 | 460 | return rc; |
| 435 | 461 | } |
| @@ -469,9 +495,9 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io · 33 unmodified lines | ||
| 469 | 495 | if (!resp) |
| 470 | 496 | return -ENOMEM; |
| 471 | 497 | |
| 472 | − rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, | |
| 498 | + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, | |
| 473 | 499 | SNP_MSG_REPORT_REQ, &req, sizeof(req), resp->data, |
| 474 | − resp_len, &arg->fw_err); | |
| 500 | + resp_len); | |
| 475 | 501 | if (rc) |
| 476 | 502 | goto e_free; |
| 477 | 503 | |
| @@ -509,9 +535,8 @@ static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_reque · 31 unmodified lines | ||
| 509 | 535 | if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) |
| 510 | 536 | return -EFAULT; |
| 511 | 537 | |
| 512 | − rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, | |
| 513 | − SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len, | |
| 514 | − &arg->fw_err); | |
| 538 | + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, | |
| 539 | + SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len); | |
| 515 | 540 | if (rc) |
| 516 | 541 | return rc; |
| 517 | 542 | |
| @@ -571,12 +596,12 @@ cmd: · 53 unmodified lines | ||
| 571 | 596 | return -ENOMEM; |
| 572 | 597 | |
| 573 | 598 | snp_dev->input.data_npages = npages; |
| 574 | − ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg->msg_version, | |
| 599 | + ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg, | |
| 575 | 600 | SNP_MSG_REPORT_REQ, &req.data, |
| 576 | − sizeof(req.data), resp->data, resp_len, &arg->fw_err); | |
| 601 | + sizeof(req.data), resp->data, resp_len); | |
| 577 | 602 | |
| 578 | 603 | /* If certs length is invalid then copy the returned length */ |
| 579 | − if (arg->fw_err == SNP_GUEST_REQ_INVALID_LEN) { | |
| 604 | + if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) { | |
| 580 | 605 | req.certs_len = snp_dev->input.data_npages << PAGE_SHIFT; |
| 581 | 606 | |
| 582 | 607 | if (copy_to_user((void __user *)arg->req_data, &req, sizeof(req))) |
| @@ -611,7 +636,7 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long · 28 unmodified lines | ||
| 611 | 636 | if (copy_from_user(&input, argp, sizeof(input))) |
| 612 | 637 | return -EFAULT; |
| 613 | 638 | |
| 614 | − input.fw_err = 0xff; | |
| 639 | + input.exitinfo2 = 0xff; | |
| 615 | 640 | |
| 616 | 641 | /* Message version must be non-zero */ |
| 617 | 642 | if (!input.msg_version) |
| @@ -642,7 +667,7 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long · 24 unmodified lines | ||
| 642 | 667 | |
| 643 | 668 | mutex_unlock(&snp_cmd_mutex); |
| 644 | 669 | |
| 645 | − if (input.fw_err && copy_to_user(argp, &input, sizeof(input))) | |
| 670 | + if (input.exitinfo2 && copy_to_user(argp, &input, sizeof(input))) | |
| 646 | 671 | return -EFAULT; |
| 647 | 672 | |
| 648 | 673 | return ret; |
| @@ -26,6 +26,8 @@ · 25 unmodified lines | ||
| 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; |
| @@ -36,6 +36,13 @@ enum { · 35 unmodified lines | ||
| 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, |
| @@ -52,8 +52,14 @@ struct snp_guest_request_ioctl { · 51 unmodified lines | ||
| 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 { |
| @@ -77,4 +83,12 @@ struct snp_ext_report_req { · 17 unmodified lines | ||
| 77 | 83 | /* Get SNP extended report as defined in the GHCB specification version 2. */ |
| 78 | 84 | #define SNP_GET_EXT_REPORT _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x2, struct snp_guest_request_ioctl) |
| 79 | 85 | |
| 86 | +/* Guest message request EXIT_INFO_2 constants */ | |
| 87 | +#define SNP_GUEST_FW_ERR_MASK GENMASK_ULL(31, 0) | |
| 88 | +#define SNP_GUEST_VMM_ERR_SHIFT 32 | |
| 89 | +#define SNP_GUEST_VMM_ERR(x) (((u64)x) << SNP_GUEST_VMM_ERR_SHIFT) | |
| 90 | + | |
| 91 | +#define SNP_GUEST_VMM_ERR_INVALID_LEN 1 | |
| 92 | +#define SNP_GUEST_VMM_ERR_BUSY 2 | |
| 93 | + | |
| 80 | 94 | #endif /* __UAPI_LINUX_SEV_GUEST_H_ */ |
| @@ -1092,14 +1092,6 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) · 1091 unmodified lines | ||
| 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) { |
| @@ -1116,6 +1108,17 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) · 10 unmodified lines | ||
| 1116 | 1108 | late_time_init(); |
| 1117 | 1109 | sched_clock_init(); |
| 1118 | 1110 | calibrate_delay(); |
| 1111 | + | |
| 1112 | + /* | |
| 1113 | + * This needs to be called before any devices perform DMA | |
| 1114 | + * operations that might use the SWIOTLB bounce buffers. It will | |
| 1115 | + * mark the bounce buffers as decrypted so that their usage will | |
| 1116 | + * not cause "plain-text" data to be decrypted when accessed. It | |
| 1117 | + * must be called after late_time_init() so that Hyper-V x86/x64 | |
| 1118 | + * hypercalls work when the SWIOTLB bounce buffers are decrypted. | |
| 1119 | + */ | |
| 1120 | + mem_encrypt_init(); | |
| 1121 | + | |
| 1119 | 1122 | pid_idr_init(); |
| 1120 | 1123 | anon_vma_init(); |
| 1121 | 1124 | #ifdef CONFIG_X86 |