Skip to content

Commit bc1bb2a

Browse files
committed
Merge tag 'x86_sev_for_v6.4_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
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
2 parents c42b59b + 812b059 commit bc1bb2a

File tree

25 files changed

+311
-168
lines changed

25 files changed

+311
-168
lines changed

Documentation/virt/coco/sev-guest.rst

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ along with a description:
3737
the return value. General error numbers (-ENOMEM, -EINVAL)
3838
are not detailed, but errors with specific meanings are.
3939

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.
4545

4646
The firmware checks that the message sequence counter is one greater than
4747
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.
5757
__u64 req_data;
5858
__u64 resp_data;
5959

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+
};
6268
};
6369

6470
2.1 SNP_GET_REPORT

arch/x86/coco/core.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ static bool intel_cc_platform_has(enum cc_attr attr)
2929
}
3030
}
3131

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+
3248
/*
3349
* SME and SEV are very similar but they are not the same, so there are
3450
* 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)
4157
* up under SME the trampoline area cannot be encrypted, whereas under SEV
4258
* the trampoline area must be encrypted.
4359
*/
60+
4461
static bool amd_cc_platform_has(enum cc_attr attr)
4562
{
4663
#ifdef CONFIG_AMD_MEM_ENCRYPT
64+
65+
if (sev_status & MSR_AMD64_SNP_VTOM)
66+
return amd_cc_platform_vtom(attr);
67+
4768
switch (attr) {
4869
case CC_ATTR_MEM_ENCRYPT:
4970
return sme_me_mask;
@@ -76,20 +97,13 @@ static bool amd_cc_platform_has(enum cc_attr attr)
7697
#endif
7798
}
7899

79-
static bool hyperv_cc_platform_has(enum cc_attr attr)
80-
{
81-
return attr == CC_ATTR_GUEST_MEM_ENCRYPT;
82-
}
83-
84100
bool cc_platform_has(enum cc_attr attr)
85101
{
86102
switch (vendor) {
87103
case CC_VENDOR_AMD:
88104
return amd_cc_platform_has(attr);
89105
case CC_VENDOR_INTEL:
90106
return intel_cc_platform_has(attr);
91-
case CC_VENDOR_HYPERV:
92-
return hyperv_cc_platform_has(attr);
93107
default:
94108
return false;
95109
}
@@ -103,11 +117,14 @@ u64 cc_mkenc(u64 val)
103117
* encryption status of the page.
104118
*
105119
* - 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
107121
*/
108122
switch (vendor) {
109123
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;
111128
case CC_VENDOR_INTEL:
112129
return val & ~cc_mask;
113130
default:
@@ -120,7 +137,10 @@ u64 cc_mkdec(u64 val)
120137
/* See comment in cc_mkenc() */
121138
switch (vendor) {
122139
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;
124144
case CC_VENDOR_INTEL:
125145
return val | cc_mask;
126146
default:

arch/x86/hyperv/hv_init.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include <linux/syscore_ops.h>
3030
#include <clocksource/hyperv_timer.h>
3131
#include <linux/highmem.h>
32-
#include <linux/swiotlb.h>
3332

3433
int hyperv_init_cpuhp;
3534
u64 hv_current_partition_id = ~0ull;
@@ -504,16 +503,6 @@ void __init hyperv_init(void)
504503
/* Query the VMs extended capability once, so that it can be cached. */
505504
hv_query_ext_cap(0);
506505

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-
517506
return;
518507

519508
clean_guest_os_id:

arch/x86/hyperv/ivm.c

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <asm/svm.h>
1414
#include <asm/sev.h>
1515
#include <asm/io.h>
16+
#include <asm/coco.h>
17+
#include <asm/mem_encrypt.h>
1618
#include <asm/mshyperv.h>
1719
#include <asm/hypervisor.h>
1820

@@ -233,41 +235,6 @@ void hv_ghcb_msr_read(u64 msr, u64 *value)
233235
local_irq_restore(flags);
234236
}
235237
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-
}
271238

272239
/*
273240
* 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[],
320287
}
321288

322289
/*
323-
* hv_set_mem_host_visibility - Set specified memory visible to host.
290+
* hv_vtom_set_host_visibility - Set specified memory visible to host.
324291
*
325292
* In Isolation VM, all guest memory is encrypted from host and guest
326293
* needs to set memory visible to host via hvcall before sharing memory
327294
* with host. This function works as wrap of hv_mark_gpa_visibility()
328295
* with memory base and size.
329296
*/
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)
331298
{
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;
334301
u64 *pfn_array;
335302
int ret = 0;
303+
bool result = true;
336304
int i, pfn;
337305

338-
if (!hv_is_isolation_supported() || !hv_hypercall_pg)
339-
return 0;
340-
341306
pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
342307
if (!pfn_array)
343-
return -ENOMEM;
308+
return false;
344309

345310
for (i = 0, pfn = 0; i < pagecount; i++) {
346311
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
349314
if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
350315
ret = hv_mark_gpa_visibility(pfn, pfn_array,
351316
visibility);
352-
if (ret)
317+
if (ret) {
318+
result = false;
353319
goto err_free_pfn_array;
320+
}
354321
pfn = 0;
355322
}
356323
}
357324

358325
err_free_pfn_array:
359326
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;
361333
}
362334

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+
363379
/*
364380
* hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM.
365381
*/
@@ -377,7 +393,7 @@ void *hv_map_memory(void *addr, unsigned long size)
377393
pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) +
378394
(ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT);
379395

380-
vaddr = vmap_pfn(pfns, size / PAGE_SIZE, PAGE_KERNEL_IO);
396+
vaddr = vmap_pfn(pfns, size / PAGE_SIZE, pgprot_decrypted(PAGE_KERNEL));
381397
kfree(pfns);
382398

383399
return vaddr;
@@ -387,3 +403,37 @@ void hv_unmap_memory(void *addr)
387403
{
388404
vunmap(addr);
389405
}
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+
}

arch/x86/include/asm/coco.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
enum cc_vendor {
88
CC_VENDOR_NONE,
99
CC_VENDOR_AMD,
10-
CC_VENDOR_HYPERV,
1110
CC_VENDOR_INTEL,
1211
};
1312

arch/x86/include/asm/mem_encrypt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ void __init sev_es_init_vc_handling(void);
5656
#else /* !CONFIG_AMD_MEM_ENCRYPT */
5757

5858
#define sme_me_mask 0ULL
59+
#define sev_status 0ULL
5960

6061
static inline void __init sme_early_encrypt(resource_size_t paddr,
6162
unsigned long size) { }

0 commit comments

Comments
 (0)