Pull hyperv updates from Wei Liu: - Initial patch set for Hyper-V isolation VM support (Tianyu Lan) - Fix a warning on preemption (Vitaly Kuznetsov) - A bunch of misc cleanup patches * tag 'hyperv-next-signed-20211102' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: x86/hyperv: Protect set_hv_tscchange_cb() against getting preempted Drivers: hv : vmbus: Adding NULL pointer check x86/hyperv: Remove duplicate include x86/hyperv: Remove duplicated include in hv_init Drivers: hv: vmbus: Remove unused code to check for subchannels Drivers: hv: vmbus: Initialize VMbus ring buffer for Isolation VM Drivers: hv: vmbus: Add SNP support for VMbus channel initiate message x86/hyperv: Add ghcb hvcall support for SNP VM x86/hyperv: Add Write/Read MSR registers via ghcb page Drivers: hv: vmbus: Mark vmbus ring buffer visible to host in Isolation VM x86/hyperv: Add new hvcall guest address host visibility support x86/hyperv: Initialize shared memory boundary in the Isolation VM. x86/hyperv: Initialize GHCB page in Isolation VM
Unified · Split
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | −obj-y := hv_init.o mmu.o nested.o irqdomain.o | |
| 2 | +obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o | |
| 3 | 3 | obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o |
| 4 | 4 | |
| 5 | 5 | ifdef CONFIG_X86_64 |
| @@ -36,12 +36,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id); · 35 unmodified lines | ||
| 36 | 36 | void *hv_hypercall_pg; |
| 37 | 37 | EXPORT_SYMBOL_GPL(hv_hypercall_pg); |
| 38 | 38 | |
| 39 | +union hv_ghcb __percpu **hv_ghcb_pg; | |
| 40 | + | |
| 39 | 41 | /* Storage to save the hypercall page temporarily for hibernation */ |
| 40 | 42 | static void *hv_hypercall_pg_saved; |
| 41 | 43 | |
| 42 | 44 | struct hv_vp_assist_page **hv_vp_assist_page; |
| 43 | 45 | EXPORT_SYMBOL_GPL(hv_vp_assist_page); |
| 44 | 46 | |
| 47 | +static int hyperv_init_ghcb(void) | |
| 48 | +{ | |
| 49 | + u64 ghcb_gpa; | |
| 50 | + void *ghcb_va; | |
| 51 | + void **ghcb_base; | |
| 52 | + | |
| 53 | + if (!hv_isolation_type_snp()) | |
| 54 | + return 0; | |
| 55 | + | |
| 56 | + if (!hv_ghcb_pg) | |
| 57 | + return -EINVAL; | |
| 58 | + | |
| 59 | + /* | |
| 60 | + * GHCB page is allocated by paravisor. The address | |
| 61 | + * returned by MSR_AMD64_SEV_ES_GHCB is above shared | |
| 62 | + * memory boundary and map it here. | |
| 63 | + */ | |
| 64 | + rdmsrl(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa); | |
| 65 | + ghcb_va = memremap(ghcb_gpa, HV_HYP_PAGE_SIZE, MEMREMAP_WB); | |
| 66 | + if (!ghcb_va) | |
| 67 | + return -ENOMEM; | |
| 68 | + | |
| 69 | + ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg); | |
| 70 | + *ghcb_base = ghcb_va; | |
| 71 | + | |
| 72 | + return 0; | |
| 73 | +} | |
| 74 | + | |
| 45 | 75 | static int hv_cpu_init(unsigned int cpu) |
| 46 | 76 | { |
| 47 | 77 | union hv_vp_assist_msr_contents msr = { 0 }; |
| @@ -85,7 +115,7 @@ static int hv_cpu_init(unsigned int cpu) · 37 unmodified lines | ||
| 85 | 115 | } |
| 86 | 116 | } |
| 87 | 117 | |
| 88 | − return 0; | |
| 118 | + return hyperv_init_ghcb(); | |
| 89 | 119 | } |
| 90 | 120 | |
| 91 | 121 | static void (*hv_reenlightenment_cb)(void); |
| @@ -139,7 +169,6 @@ void set_hv_tscchange_cb(void (*cb)(void)) · 47 unmodified lines | ||
| 139 | 169 | struct hv_reenlightenment_control re_ctrl = { |
| 140 | 170 | .vector = HYPERV_REENLIGHTENMENT_VECTOR, |
| 141 | 171 | .enabled = 1, |
| 142 | − .target_vp = hv_vp_index[smp_processor_id()] | |
| 143 | 172 | }; |
| 144 | 173 | struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; |
| 145 | 174 | |
| @@ -153,8 +182,12 @@ void set_hv_tscchange_cb(void (*cb)(void)) · 7 unmodified lines | ||
| 153 | 182 | /* Make sure callback is registered before we write to MSRs */ |
| 154 | 183 | wmb(); |
| 155 | 184 | |
| 185 | + re_ctrl.target_vp = hv_vp_index[get_cpu()]; | |
| 186 | + | |
| 156 | 187 | wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); |
| 157 | 188 | wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); |
| 189 | + | |
| 190 | + put_cpu(); | |
| 158 | 191 | } |
| 159 | 192 | EXPORT_SYMBOL_GPL(set_hv_tscchange_cb); |
| 160 | 193 | |
| @@ -177,6 +210,14 @@ static int hv_cpu_die(unsigned int cpu) · 16 unmodified lines | ||
| 177 | 210 | { |
| 178 | 211 | struct hv_reenlightenment_control re_ctrl; |
| 179 | 212 | unsigned int new_cpu; |
| 213 | + void **ghcb_va; | |
| 214 | + | |
| 215 | + if (hv_ghcb_pg) { | |
| 216 | + ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg); | |
| 217 | + if (*ghcb_va) | |
| 218 | + memunmap(*ghcb_va); | |
| 219 | + *ghcb_va = NULL; | |
| 220 | + } | |
| 180 | 221 | |
| 181 | 222 | hv_common_cpu_die(cpu); |
| 182 | 223 | |
| @@ -366,10 +407,16 @@ void __init hyperv_init(void) · 183 unmodified lines | ||
| 366 | 407 | goto common_free; |
| 367 | 408 | } |
| 368 | 409 | |
| 410 | + if (hv_isolation_type_snp()) { | |
| 411 | + hv_ghcb_pg = alloc_percpu(union hv_ghcb *); | |
| 412 | + if (!hv_ghcb_pg) | |
| 413 | + goto free_vp_assist_page; | |
| 414 | + } | |
| 415 | + | |
| 369 | 416 | cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online", |
| 370 | 417 | hv_cpu_init, hv_cpu_die); |
| 371 | 418 | if (cpuhp < 0) |
| 372 | − goto free_vp_assist_page; | |
| 419 | + goto free_ghcb_page; | |
| 373 | 420 | |
| 374 | 421 | /* |
| 375 | 422 | * Setup the hypercall page and enable hypercalls. |
| @@ -379,14 +426,15 @@ void __init hyperv_init(void) · 3 unmodified lines | ||
| 379 | 426 | guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); |
| 380 | 427 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); |
| 381 | 428 | |
| 429 | + /* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ | |
| 430 | + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id); | |
| 431 | + | |
| 382 | 432 | hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, |
| 383 | 433 | VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, |
| 384 | 434 | VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, |
| 385 | 435 | __builtin_return_address(0)); |
| 386 | − if (hv_hypercall_pg == NULL) { | |
| 387 | − wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | |
| 388 | − goto remove_cpuhp_state; | |
| 389 | − } | |
| 436 | + if (hv_hypercall_pg == NULL) | |
| 437 | + goto clean_guest_os_id; | |
| 390 | 438 | |
| 391 | 439 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); |
| 392 | 440 | hypercall_msr.enable = 1; |
| @@ -456,8 +504,12 @@ void __init hyperv_init(void) · 63 unmodified lines | ||
| 456 | 504 | hv_query_ext_cap(0); |
| 457 | 505 | return; |
| 458 | 506 | |
| 459 | −remove_cpuhp_state: | |
| 507 | +clean_guest_os_id: | |
| 508 | + wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | |
| 509 | + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); | |
| 460 | 510 | cpuhp_remove_state(cpuhp); |
| 511 | +free_ghcb_page: | |
| 512 | + free_percpu(hv_ghcb_pg); | |
| 461 | 513 | free_vp_assist_page: |
| 462 | 514 | kfree(hv_vp_assist_page); |
| 463 | 515 | hv_vp_assist_page = NULL; |
| @@ -476,6 +528,7 @@ void hyperv_cleanup(void) · 12 unmodified lines | ||
| 476 | 528 | |
| 477 | 529 | /* Reset our OS id */ |
| 478 | 530 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); |
| 531 | + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); | |
| 479 | 532 | |
| 480 | 533 | /* |
| 481 | 534 | * Reset hypercall page reference before reset the page, |
| @@ -546,16 +599,3 @@ bool hv_is_hyperv_initialized(void) · 64 unmodified lines | ||
| 546 | 599 | return hypercall_msr.enable; |
| 547 | 600 | } |
| 548 | 601 | EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized); |
| 549 | − | |
| 550 | −enum hv_isolation_type hv_get_isolation_type(void) | |
| 551 | −{ | |
| 552 | − if (!(ms_hyperv.priv_high & HV_ISOLATION)) | |
| 553 | − return HV_ISOLATION_TYPE_NONE; | |
| 554 | − return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); | |
| 555 | −} | |
| 556 | −EXPORT_SYMBOL_GPL(hv_get_isolation_type); | |
| 557 | − | |
| 558 | −bool hv_is_isolation_supported(void) | |
| 559 | −{ | |
| 560 | − return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; | |
| 561 | −} | |
| @@ -0,0 +1,289 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Hyper-V Isolation VM interface with paravisor and hypervisor | |
| 4 | + * | |
| 5 | + * Author: | |
| 6 | + * Tianyu Lan <Tianyu.Lan@microsoft.com> | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/bitfield.h> | |
| 10 | +#include <linux/hyperv.h> | |
| 11 | +#include <linux/types.h> | |
| 12 | +#include <linux/slab.h> | |
| 13 | +#include <asm/svm.h> | |
| 14 | +#include <asm/sev.h> | |
| 15 | +#include <asm/io.h> | |
| 16 | +#include <asm/mshyperv.h> | |
| 17 | +#include <asm/hypervisor.h> | |
| 18 | + | |
| 19 | +#ifdef CONFIG_AMD_MEM_ENCRYPT | |
| 20 | + | |
| 21 | +#define GHCB_USAGE_HYPERV_CALL 1 | |
| 22 | + | |
| 23 | +union hv_ghcb { | |
| 24 | + struct ghcb ghcb; | |
| 25 | + struct { | |
| 26 | + u64 hypercalldata[509]; | |
| 27 | + u64 outputgpa; | |
| 28 | + union { | |
| 29 | + union { | |
| 30 | + struct { | |
| 31 | + u32 callcode : 16; | |
| 32 | + u32 isfast : 1; | |
| 33 | + u32 reserved1 : 14; | |
| 34 | + u32 isnested : 1; | |
| 35 | + u32 countofelements : 12; | |
| 36 | + u32 reserved2 : 4; | |
| 37 | + u32 repstartindex : 12; | |
| 38 | + u32 reserved3 : 4; | |
| 39 | + }; | |
| 40 | + u64 asuint64; | |
| 41 | + } hypercallinput; | |
| 42 | + union { | |
| 43 | + struct { | |
| 44 | + u16 callstatus; | |
| 45 | + u16 reserved1; | |
| 46 | + u32 elementsprocessed : 12; | |
| 47 | + u32 reserved2 : 20; | |
| 48 | + }; | |
| 49 | + u64 asunit64; | |
| 50 | + } hypercalloutput; | |
| 51 | + }; | |
| 52 | + u64 reserved2; | |
| 53 | + } hypercall; | |
| 54 | +} __packed __aligned(HV_HYP_PAGE_SIZE); | |
| 55 | + | |
| 56 | +u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size) | |
| 57 | +{ | |
| 58 | + union hv_ghcb *hv_ghcb; | |
| 59 | + void **ghcb_base; | |
| 60 | + unsigned long flags; | |
| 61 | + u64 status; | |
| 62 | + | |
| 63 | + if (!hv_ghcb_pg) | |
| 64 | + return -EFAULT; | |
| 65 | + | |
| 66 | + WARN_ON(in_nmi()); | |
| 67 | + | |
| 68 | + local_irq_save(flags); | |
| 69 | + ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg); | |
| 70 | + hv_ghcb = (union hv_ghcb *)*ghcb_base; | |
| 71 | + if (!hv_ghcb) { | |
| 72 | + local_irq_restore(flags); | |
| 73 | + return -EFAULT; | |
| 74 | + } | |
| 75 | + | |
| 76 | + hv_ghcb->ghcb.protocol_version = GHCB_PROTOCOL_MAX; | |
| 77 | + hv_ghcb->ghcb.ghcb_usage = GHCB_USAGE_HYPERV_CALL; | |
| 78 | + | |
| 79 | + hv_ghcb->hypercall.outputgpa = (u64)output; | |
| 80 | + hv_ghcb->hypercall.hypercallinput.asuint64 = 0; | |
| 81 | + hv_ghcb->hypercall.hypercallinput.callcode = control; | |
| 82 | + | |
| 83 | + if (input_size) | |
| 84 | + memcpy(hv_ghcb->hypercall.hypercalldata, input, input_size); | |
| 85 | + | |
| 86 | + VMGEXIT(); | |
| 87 | + | |
| 88 | + hv_ghcb->ghcb.ghcb_usage = 0xffffffff; | |
| 89 | + memset(hv_ghcb->ghcb.save.valid_bitmap, 0, | |
| 90 | + sizeof(hv_ghcb->ghcb.save.valid_bitmap)); | |
| 91 | + | |
| 92 | + status = hv_ghcb->hypercall.hypercalloutput.callstatus; | |
| 93 | + | |
| 94 | + local_irq_restore(flags); | |
| 95 | + | |
| 96 | + return status; | |
| 97 | +} | |
| 98 | + | |
| 99 | +void hv_ghcb_msr_write(u64 msr, u64 value) | |
| 100 | +{ | |
| 101 | + union hv_ghcb *hv_ghcb; | |
| 102 | + void **ghcb_base; | |
| 103 | + unsigned long flags; | |
| 104 | + struct es_em_ctxt ctxt; | |
| 105 | + | |
| 106 | + if (!hv_ghcb_pg) | |
| 107 | + return; | |
| 108 | + | |
| 109 | + WARN_ON(in_nmi()); | |
| 110 | + | |
| 111 | + local_irq_save(flags); | |
| 112 | + ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg); | |
| 113 | + hv_ghcb = (union hv_ghcb *)*ghcb_base; | |
| 114 | + if (!hv_ghcb) { | |
| 115 | + local_irq_restore(flags); | |
| 116 | + return; | |
| 117 | + } | |
| 118 | + | |
| 119 | + ghcb_set_rcx(&hv_ghcb->ghcb, msr); | |
| 120 | + ghcb_set_rax(&hv_ghcb->ghcb, lower_32_bits(value)); | |
| 121 | + ghcb_set_rdx(&hv_ghcb->ghcb, upper_32_bits(value)); | |
| 122 | + | |
| 123 | + if (sev_es_ghcb_hv_call(&hv_ghcb->ghcb, false, &ctxt, | |
| 124 | + SVM_EXIT_MSR, 1, 0)) | |
| 125 | + pr_warn("Fail to write msr via ghcb %llx.\n", msr); | |
| 126 | + | |
| 127 | + local_irq_restore(flags); | |
| 128 | +} | |
| 129 | +EXPORT_SYMBOL_GPL(hv_ghcb_msr_write); | |
| 130 | + | |
| 131 | +void hv_ghcb_msr_read(u64 msr, u64 *value) | |
| 132 | +{ | |
| 133 | + union hv_ghcb *hv_ghcb; | |
| 134 | + void **ghcb_base; | |
| 135 | + unsigned long flags; | |
| 136 | + struct es_em_ctxt ctxt; | |
| 137 | + | |
| 138 | + /* Check size of union hv_ghcb here. */ | |
| 139 | + BUILD_BUG_ON(sizeof(union hv_ghcb) != HV_HYP_PAGE_SIZE); | |
| 140 | + | |
| 141 | + if (!hv_ghcb_pg) | |
| 142 | + return; | |
| 143 | + | |
| 144 | + WARN_ON(in_nmi()); | |
| 145 | + | |
| 146 | + local_irq_save(flags); | |
| 147 | + ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg); | |
| 148 | + hv_ghcb = (union hv_ghcb *)*ghcb_base; | |
| 149 | + if (!hv_ghcb) { | |
| 150 | + local_irq_restore(flags); | |
| 151 | + return; | |
| 152 | + } | |
| 153 | + | |
| 154 | + ghcb_set_rcx(&hv_ghcb->ghcb, msr); | |
| 155 | + if (sev_es_ghcb_hv_call(&hv_ghcb->ghcb, false, &ctxt, | |
| 156 | + SVM_EXIT_MSR, 0, 0)) | |
| 157 | + pr_warn("Fail to read msr via ghcb %llx.\n", msr); | |
| 158 | + else | |
| 159 | + *value = (u64)lower_32_bits(hv_ghcb->ghcb.save.rax) | |
| 160 | + | ((u64)lower_32_bits(hv_ghcb->ghcb.save.rdx) << 32); | |
| 161 | + local_irq_restore(flags); | |
| 162 | +} | |
| 163 | +EXPORT_SYMBOL_GPL(hv_ghcb_msr_read); | |
| 164 | +#endif | |
| 165 | + | |
| 166 | +enum hv_isolation_type hv_get_isolation_type(void) | |
| 167 | +{ | |
| 168 | + if (!(ms_hyperv.priv_high & HV_ISOLATION)) | |
| 169 | + return HV_ISOLATION_TYPE_NONE; | |
| 170 | + return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); | |
| 171 | +} | |
| 172 | +EXPORT_SYMBOL_GPL(hv_get_isolation_type); | |
| 173 | + | |
| 174 | +/* | |
| 175 | + * hv_is_isolation_supported - Check system runs in the Hyper-V | |
| 176 | + * isolation VM. | |
| 177 | + */ | |
| 178 | +bool hv_is_isolation_supported(void) | |
| 179 | +{ | |
| 180 | + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) | |
| 181 | + return false; | |
| 182 | + | |
| 183 | + if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) | |
| 184 | + return false; | |
| 185 | + | |
| 186 | + return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; | |
| 187 | +} | |
| 188 | + | |
| 189 | +DEFINE_STATIC_KEY_FALSE(isolation_type_snp); | |
| 190 | + | |
| 191 | +/* | |
| 192 | + * hv_isolation_type_snp - Check system runs in the AMD SEV-SNP based | |
| 193 | + * isolation VM. | |
| 194 | + */ | |
| 195 | +bool hv_isolation_type_snp(void) | |
| 196 | +{ | |
| 197 | + return static_branch_unlikely(&isolation_type_snp); | |
| 198 | +} | |
| 199 | + | |
| 200 | +/* | |
| 201 | + * hv_mark_gpa_visibility - Set pages visible to host via hvcall. | |
| 202 | + * | |
| 203 | + * In Isolation VM, all guest memory is encrypted from host and guest | |
| 204 | + * needs to set memory visible to host via hvcall before sharing memory | |
| 205 | + * with host. | |
| 206 | + */ | |
| 207 | +static int hv_mark_gpa_visibility(u16 count, const u64 pfn[], | |
| 208 | + enum hv_mem_host_visibility visibility) | |
| 209 | +{ | |
| 210 | + struct hv_gpa_range_for_visibility **input_pcpu, *input; | |
| 211 | + u16 pages_processed; | |
| 212 | + u64 hv_status; | |
| 213 | + unsigned long flags; | |
| 214 | + | |
| 215 | + /* no-op if partition isolation is not enabled */ | |
| 216 | + if (!hv_is_isolation_supported()) | |
| 217 | + return 0; | |
| 218 | + | |
| 219 | + if (count > HV_MAX_MODIFY_GPA_REP_COUNT) { | |
| 220 | + pr_err("Hyper-V: GPA count:%d exceeds supported:%lu\n", count, | |
| 221 | + HV_MAX_MODIFY_GPA_REP_COUNT); | |
| 222 | + return -EINVAL; | |
| 223 | + } | |
| 224 | + | |
| 225 | + local_irq_save(flags); | |
| 226 | + input_pcpu = (struct hv_gpa_range_for_visibility **) | |
| 227 | + this_cpu_ptr(hyperv_pcpu_input_arg); | |
| 228 | + input = *input_pcpu; | |
| 229 | + if (unlikely(!input)) { | |
| 230 | + local_irq_restore(flags); | |
| 231 | + return -EINVAL; | |
| 232 | + } | |
| 233 | + | |
| 234 | + input->partition_id = HV_PARTITION_ID_SELF; | |
| 235 | + input->host_visibility = visibility; | |
| 236 | + input->reserved0 = 0; | |
| 237 | + input->reserved1 = 0; | |
| 238 | + memcpy((void *)input->gpa_page_list, pfn, count * sizeof(*pfn)); | |
| 239 | + hv_status = hv_do_rep_hypercall( | |
| 240 | + HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY, count, | |
| 241 | + 0, input, &pages_processed); | |
| 242 | + local_irq_restore(flags); | |
| 243 | + | |
| 244 | + if (hv_result_success(hv_status)) | |
| 245 | + return 0; | |
| 246 | + else | |
| 247 | + return -EFAULT; | |
| 248 | +} | |
| 249 | + | |
| 250 | +/* | |
| 251 | + * hv_set_mem_host_visibility - Set specified memory visible to host. | |
| 252 | + * | |
| 253 | + * In Isolation VM, all guest memory is encrypted from host and guest | |
| 254 | + * needs to set memory visible to host via hvcall before sharing memory | |
| 255 | + * with host. This function works as wrap of hv_mark_gpa_visibility() | |
| 256 | + * with memory base and size. | |
| 257 | + */ | |
| 258 | +int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visible) | |
| 259 | +{ | |
| 260 | + enum hv_mem_host_visibility visibility = visible ? | |
| 261 | + VMBUS_PAGE_VISIBLE_READ_WRITE : VMBUS_PAGE_NOT_VISIBLE; | |
| 262 | + u64 *pfn_array; | |
| 263 | + int ret = 0; | |
| 264 | + int i, pfn; | |
| 265 | + | |
| 266 | + if (!hv_is_isolation_supported() || !hv_hypercall_pg) | |
| 267 | + return 0; | |
| 268 | + | |
| 269 | + pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); | |
| 270 | + if (!pfn_array) | |
| 271 | + return -ENOMEM; | |
| 272 | + | |
| 273 | + for (i = 0, pfn = 0; i < pagecount; i++) { | |
| 274 | + pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE); | |
| 275 | + pfn++; | |
| 276 | + | |
| 277 | + if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) { | |
| 278 | + ret = hv_mark_gpa_visibility(pfn, pfn_array, | |
| 279 | + visibility); | |
| 280 | + if (ret) | |
| 281 | + goto err_free_pfn_array; | |
| 282 | + pfn = 0; | |
| 283 | + } | |
| 284 | + } | |
| 285 | + | |
| 286 | + err_free_pfn_array: | |
| 287 | + kfree(pfn_array); | |
| 288 | + return ret; | |
| 289 | +} | |
| @@ -276,6 +276,23 @@ enum hv_isolation_type { · 275 unmodified lines | ||
| 276 | 276 | #define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT |
| 277 | 277 | #define HV_X64_MSR_REFERENCE_TSC HV_REGISTER_REFERENCE_TSC |
| 278 | 278 | |
| 279 | +/* Hyper-V memory host visibility */ | |
| 280 | +enum hv_mem_host_visibility { | |
| 281 | + VMBUS_PAGE_NOT_VISIBLE = 0, | |
| 282 | + VMBUS_PAGE_VISIBLE_READ_ONLY = 1, | |
| 283 | + VMBUS_PAGE_VISIBLE_READ_WRITE = 3 | |
| 284 | +}; | |
| 285 | + | |
| 286 | +/* HvCallModifySparseGpaPageHostVisibility hypercall */ | |
| 287 | +#define HV_MAX_MODIFY_GPA_REP_COUNT ((PAGE_SIZE / sizeof(u64)) - 2) | |
| 288 | +struct hv_gpa_range_for_visibility { | |
| 289 | + u64 partition_id; | |
| 290 | + u32 host_visibility:2; | |
| 291 | + u32 reserved0:30; | |
| 292 | + u32 reserved1; | |
| 293 | + u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT]; | |
| 294 | +} __packed; | |
| 295 | + | |
| 279 | 296 | /* |
| 280 | 297 | * Declare the MSR used to setup pages used to communicate with the hypervisor. |
| 281 | 298 | */ |
| @@ -11,23 +11,14 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <asm/paravirt.h> |
| 12 | 12 | #include <asm/mshyperv.h> |
| 13 | 13 | |
| 14 | +union hv_ghcb; | |
| 15 | + | |
| 16 | +DECLARE_STATIC_KEY_FALSE(isolation_type_snp); | |
| 17 | + | |
| 14 | 18 | typedef int (*hyperv_fill_flush_list_func)( |
| 15 | 19 | struct hv_guest_mapping_flush_list *flush, |
| 16 | 20 | void *data); |
| 17 | 21 | |
| 18 | −static inline void hv_set_register(unsigned int reg, u64 value) | |
| 19 | −{ | |
| 20 | − wrmsrl(reg, value); | |
| 21 | −} | |
| 22 | − | |
| 23 | −static inline u64 hv_get_register(unsigned int reg) | |
| 24 | −{ | |
| 25 | − u64 value; | |
| 26 | − | |
| 27 | − rdmsrl(reg, value); | |
| 28 | − return value; | |
| 29 | −} | |
| 30 | − | |
| 31 | 22 | #define hv_get_raw_timer() rdtsc_ordered() |
| 32 | 23 | |
| 33 | 24 | void hyperv_vector_handler(struct pt_regs *regs); |
| @@ -39,6 +30,8 @@ extern void *hv_hypercall_pg; · 5 unmodified lines | ||
| 39 | 30 | |
| 40 | 31 | extern u64 hv_current_partition_id; |
| 41 | 32 | |
| 33 | +extern union hv_ghcb __percpu **hv_ghcb_pg; | |
| 34 | + | |
| 42 | 35 | int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); |
| 43 | 36 | int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); |
| 44 | 37 | int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags); |
| @@ -188,6 +181,50 @@ struct irq_domain *hv_create_pci_msi_domain(void); · 143 unmodified lines | ||
| 188 | 181 | int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, |
| 189 | 182 | struct hv_interrupt_entry *entry); |
| 190 | 183 | int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); |
| 184 | +int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible); | |
| 185 | + | |
| 186 | +#ifdef CONFIG_AMD_MEM_ENCRYPT | |
| 187 | +void hv_ghcb_msr_write(u64 msr, u64 value); | |
| 188 | +void hv_ghcb_msr_read(u64 msr, u64 *value); | |
| 189 | +#else | |
| 190 | +static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} | |
| 191 | +static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {} | |
| 192 | +#endif | |
| 193 | + | |
| 194 | +extern bool hv_isolation_type_snp(void); | |
| 195 | + | |
| 196 | +static inline bool hv_is_synic_reg(unsigned int reg) | |
| 197 | +{ | |
| 198 | + if ((reg >= HV_REGISTER_SCONTROL) && | |
| 199 | + (reg <= HV_REGISTER_SINT15)) | |
| 200 | + return true; | |
| 201 | + return false; | |
| 202 | +} | |
| 203 | + | |
| 204 | +static inline u64 hv_get_register(unsigned int reg) | |
| 205 | +{ | |
| 206 | + u64 value; | |
| 207 | + | |
| 208 | + if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) | |
| 209 | + hv_ghcb_msr_read(reg, &value); | |
| 210 | + else | |
| 211 | + rdmsrl(reg, value); | |
| 212 | + return value; | |
| 213 | +} | |
| 214 | + | |
| 215 | +static inline void hv_set_register(unsigned int reg, u64 value) | |
| 216 | +{ | |
| 217 | + if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) { | |
| 218 | + hv_ghcb_msr_write(reg, value); | |
| 219 | + | |
| 220 | + /* Write proxy bit via wrmsl instruction */ | |
| 221 | + if (reg >= HV_REGISTER_SINT0 && | |
| 222 | + reg <= HV_REGISTER_SINT15) | |
| 223 | + wrmsrl(reg, value | 1 << 20); | |
| 224 | + } else { | |
| 225 | + wrmsrl(reg, value); | |
| 226 | + } | |
| 227 | +} | |
| 191 | 228 | |
| 192 | 229 | #else /* CONFIG_HYPERV */ |
| 193 | 230 | static inline void hyperv_init(void) {} |
| @@ -205,6 +242,13 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, · 11 unmodified lines | ||
| 205 | 242 | { |
| 206 | 243 | return -1; |
| 207 | 244 | } |
| 245 | +static inline void hv_set_register(unsigned int reg, u64 value) { } | |
| 246 | +static inline u64 hv_get_register(unsigned int reg) { return 0; } | |
| 247 | +static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages, | |
| 248 | + bool visible) | |
| 249 | +{ | |
| 250 | + return -1; | |
| 251 | +} | |
| 208 | 252 | #endif /* CONFIG_HYPERV */ |
| 209 | 253 | |
| 210 | 254 | |
| @@ -313,9 +313,14 @@ static void __init ms_hyperv_init_platform(void) · 312 unmodified lines | ||
| 313 | 313 | if (ms_hyperv.priv_high & HV_ISOLATION) { |
| 314 | 314 | ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); |
| 315 | 315 | ms_hyperv.isolation_config_b = cpuid_ebx(HYPERV_CPUID_ISOLATION_CONFIG); |
| 316 | + ms_hyperv.shared_gpa_boundary = | |
| 317 | + BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); | |
| 316 | 318 | |
| 317 | 319 | pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", |
| 318 | 320 | ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); |
| 321 | + | |
| 322 | + if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) | |
| 323 | + static_branch_enable(&isolation_type_snp); | |
| 319 | 324 | } |
| 320 | 325 | |
| 321 | 326 | if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { |
| @@ -30,6 +30,8 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <asm/proto.h> |
| 31 | 31 | #include <asm/memtype.h> |
| 32 | 32 | #include <asm/set_memory.h> |
| 33 | +#include <asm/hyperv-tlfs.h> | |
| 34 | +#include <asm/mshyperv.h> | |
| 33 | 35 | |
| 34 | 36 | #include "../mm_internal.h" |
| 35 | 37 | |
| @@ -1981,15 +1983,15 @@ int set_memory_global(unsigned long addr, int numpages) · 1945 unmodified lines | ||
| 1981 | 1983 | __pgprot(_PAGE_GLOBAL), 0); |
| 1982 | 1984 | } |
| 1983 | 1985 | |
| 1984 | −static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) | |
| 1986 | +/* | |
| 1987 | + * __set_memory_enc_pgtable() is used for the hypervisors that get | |
| 1988 | + * informed about "encryption" status via page tables. | |
| 1989 | + */ | |
| 1990 | +static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc) | |
| 1985 | 1991 | { |
| 1986 | 1992 | struct cpa_data cpa; |
| 1987 | 1993 | int ret; |
| 1988 | 1994 | |
| 1989 | − /* Nothing to do if memory encryption is not active */ | |
| 1990 | − if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT)) | |
| 1991 | − return 0; | |
| 1992 | − | |
| 1993 | 1995 | /* Should not be working on unaligned addresses */ |
| 1994 | 1996 | if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr)) |
| 1995 | 1997 | addr &= PAGE_MASK; |
| @@ -2024,6 +2026,17 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) · 28 unmodified lines | ||
| 2024 | 2026 | return ret; |
| 2025 | 2027 | } |
| 2026 | 2028 | |
| 2029 | +static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) | |
| 2030 | +{ | |
| 2031 | + if (hv_is_isolation_supported()) | |
| 2032 | + return hv_set_mem_host_visibility(addr, numpages, !enc); | |
| 2033 | + | |
| 2034 | + if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) | |
| 2035 | + return __set_memory_enc_pgtable(addr, numpages, enc); | |
| 2036 | + | |
| 2037 | + return 0; | |
| 2038 | +} | |
| 2039 | + | |
| 2027 | 2040 | int set_memory_encrypted(unsigned long addr, int numpages) |
| 2028 | 2041 | { |
| 2029 | 2042 | return __set_memory_enc_dec(addr, numpages, true); |
| @@ -8,6 +8,7 @@ config HYPERV · 7 unmodified lines | ||
| 8 | 8 | || (ARM64 && !CPU_BIG_ENDIAN)) |
| 9 | 9 | select PARAVIRT |
| 10 | 10 | select X86_HV_CALLBACK_VECTOR if X86 |
| 11 | + select VMAP_PFN | |
| 11 | 12 | help |
| 12 | 13 | Select this option to run Linux as a Hyper-V client operating |
| 13 | 14 | system. |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/hyperv.h> |
| 18 | 18 | #include <linux/uio.h> |
| 19 | 19 | #include <linux/interrupt.h> |
| 20 | +#include <linux/set_memory.h> | |
| 20 | 21 | #include <asm/page.h> |
| 21 | 22 | #include <asm/mshyperv.h> |
| 22 | 23 | |
| @@ -456,7 +457,7 @@ nomem: · 433 unmodified lines | ||
| 456 | 457 | static int __vmbus_establish_gpadl(struct vmbus_channel *channel, |
| 457 | 458 | enum hv_gpadl_type type, void *kbuffer, |
| 458 | 459 | u32 size, u32 send_offset, |
| 459 | − u32 *gpadl_handle) | |
| 460 | + struct vmbus_gpadl *gpadl) | |
| 460 | 461 | { |
| 461 | 462 | struct vmbus_channel_gpadl_header *gpadlmsg; |
| 462 | 463 | struct vmbus_channel_gpadl_body *gpadl_body; |
| @@ -474,6 +475,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, · 11 unmodified lines | ||
| 474 | 475 | if (ret) |
| 475 | 476 | return ret; |
| 476 | 477 | |
| 478 | + ret = set_memory_decrypted((unsigned long)kbuffer, | |
| 479 | + PFN_UP(size)); | |
| 480 | + if (ret) { | |
| 481 | + dev_warn(&channel->device_obj->device, | |
| 482 | + "Failed to set host visibility for new GPADL %d.\n", | |
| 483 | + ret); | |
| 484 | + return ret; | |
| 485 | + } | |
| 486 | + | |
| 477 | 487 | init_completion(&msginfo->waitevent); |
| 478 | 488 | msginfo->waiting_channel = channel; |
| 479 | 489 | |
| @@ -537,7 +547,10 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, · 57 unmodified lines | ||
| 537 | 547 | } |
| 538 | 548 | |
| 539 | 549 | /* At this point, we received the gpadl created msg */ |
| 540 | − *gpadl_handle = gpadlmsg->gpadl; | |
| 550 | + gpadl->gpadl_handle = gpadlmsg->gpadl; | |
| 551 | + gpadl->buffer = kbuffer; | |
| 552 | + gpadl->size = size; | |
| 553 | + | |
| 541 | 554 | |
| 542 | 555 | cleanup: |
| 543 | 556 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
| @@ -549,6 +562,11 @@ cleanup: · 5 unmodified lines | ||
| 549 | 562 | } |
| 550 | 563 | |
| 551 | 564 | kfree(msginfo); |
| 565 | + | |
| 566 | + if (ret) | |
| 567 | + set_memory_encrypted((unsigned long)kbuffer, | |
| 568 | + PFN_UP(size)); | |
| 569 | + | |
| 552 | 570 | return ret; |
| 553 | 571 | } |
| 554 | 572 | |
| @@ -561,10 +579,10 @@ cleanup: · 6 unmodified lines | ||
| 561 | 579 | * @gpadl_handle: some funky thing |
| 562 | 580 | */ |
| 563 | 581 | int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, |
| 564 | − u32 size, u32 *gpadl_handle) | |
| 582 | + u32 size, struct vmbus_gpadl *gpadl) | |
| 565 | 583 | { |
| 566 | 584 | return __vmbus_establish_gpadl(channel, HV_GPADL_BUFFER, kbuffer, size, |
| 567 | − 0U, gpadl_handle); | |
| 585 | + 0U, gpadl); | |
| 568 | 586 | } |
| 569 | 587 | EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); |
| 570 | 588 | |
| @@ -665,17 +683,8 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 94 unmodified lines | ||
| 665 | 683 | if (!newchannel->max_pkt_size) |
| 666 | 684 | newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE; |
| 667 | 685 | |
| 668 | − err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages, 0); | |
| 669 | − if (err) | |
| 670 | − goto error_clean_ring; | |
| 671 | − | |
| 672 | − err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages], | |
| 673 | − recv_pages, newchannel->max_pkt_size); | |
| 674 | − if (err) | |
| 675 | − goto error_clean_ring; | |
| 676 | − | |
| 677 | 686 | /* Establish the gpadl for the ring buffer */ |
| 678 | − newchannel->ringbuffer_gpadlhandle = 0; | |
| 687 | + newchannel->ringbuffer_gpadlhandle.gpadl_handle = 0; | |
| 679 | 688 | |
| 680 | 689 | err = __vmbus_establish_gpadl(newchannel, HV_GPADL_RING, |
| 681 | 690 | page_address(newchannel->ringbuffer_page), |
| @@ -685,6 +694,16 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 3 unmodified lines | ||
| 685 | 694 | if (err) |
| 686 | 695 | goto error_clean_ring; |
| 687 | 696 | |
| 697 | + err = hv_ringbuffer_init(&newchannel->outbound, | |
| 698 | + page, send_pages, 0); | |
| 699 | + if (err) | |
| 700 | + goto error_free_gpadl; | |
| 701 | + | |
| 702 | + err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages], | |
| 703 | + recv_pages, newchannel->max_pkt_size); | |
| 704 | + if (err) | |
| 705 | + goto error_free_gpadl; | |
| 706 | + | |
| 688 | 707 | /* Create and init the channel open message */ |
| 689 | 708 | open_info = kzalloc(sizeof(*open_info) + |
| 690 | 709 | sizeof(struct vmbus_channel_open_channel), |
| @@ -701,7 +720,8 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 10 unmodified lines | ||
| 701 | 720 | open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL; |
| 702 | 721 | open_msg->openid = newchannel->offermsg.child_relid; |
| 703 | 722 | open_msg->child_relid = newchannel->offermsg.child_relid; |
| 704 | − open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; | |
| 723 | + open_msg->ringbuffer_gpadlhandle | |
| 724 | + = newchannel->ringbuffer_gpadlhandle.gpadl_handle; | |
| 705 | 725 | /* |
| 706 | 726 | * The unit of ->downstream_ringbuffer_pageoffset is HV_HYP_PAGE and |
| 707 | 727 | * the unit of ->ringbuffer_send_offset (i.e. send_pages) is PAGE, so |
| @@ -759,8 +779,7 @@ error_clean_msglist: · 51 unmodified lines | ||
| 759 | 779 | error_free_info: |
| 760 | 780 | kfree(open_info); |
| 761 | 781 | error_free_gpadl: |
| 762 | − vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); | |
| 763 | − newchannel->ringbuffer_gpadlhandle = 0; | |
| 782 | + vmbus_teardown_gpadl(newchannel, &newchannel->ringbuffer_gpadlhandle); | |
| 764 | 783 | error_clean_ring: |
| 765 | 784 | hv_ringbuffer_cleanup(&newchannel->outbound); |
| 766 | 785 | hv_ringbuffer_cleanup(&newchannel->inbound); |
| @@ -806,7 +825,7 @@ EXPORT_SYMBOL_GPL(vmbus_open); · 39 unmodified lines | ||
| 806 | 825 | /* |
| 807 | 826 | * vmbus_teardown_gpadl -Teardown the specified GPADL handle |
| 808 | 827 | */ |
| 809 | −int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) | |
| 828 | +int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpadl) | |
| 810 | 829 | { |
| 811 | 830 | struct vmbus_channel_gpadl_teardown *msg; |
| 812 | 831 | struct vmbus_channel_msginfo *info; |
| @@ -825,7 +844,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) · 12 unmodified lines | ||
| 825 | 844 | |
| 826 | 845 | msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; |
| 827 | 846 | msg->child_relid = channel->offermsg.child_relid; |
| 828 | − msg->gpadl = gpadl_handle; | |
| 847 | + msg->gpadl = gpadl->gpadl_handle; | |
| 829 | 848 | |
| 830 | 849 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
| 831 | 850 | list_add_tail(&info->msglistentry, |
| @@ -845,6 +864,8 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) · 13 unmodified lines | ||
| 845 | 864 | |
| 846 | 865 | wait_for_completion(&info->waitevent); |
| 847 | 866 | |
| 867 | + gpadl->gpadl_handle = 0; | |
| 868 | + | |
| 848 | 869 | post_msg_err: |
| 849 | 870 | /* |
| 850 | 871 | * If the channel has been rescinded; |
| @@ -859,6 +880,12 @@ post_msg_err: · 8 unmodified lines | ||
| 859 | 880 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
| 860 | 881 | |
| 861 | 882 | kfree(info); |
| 883 | + | |
| 884 | + ret = set_memory_encrypted((unsigned long)gpadl->buffer, | |
| 885 | + PFN_UP(gpadl->size)); | |
| 886 | + if (ret) | |
| 887 | + pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret); | |
| 888 | + | |
| 862 | 889 | return ret; |
| 863 | 890 | } |
| 864 | 891 | EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); |
| @@ -933,9 +960,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel) · 68 unmodified lines | ||
| 933 | 960 | } |
| 934 | 961 | |
| 935 | 962 | /* Tear down the gpadl for the channel's ring buffer */ |
| 936 | − else if (channel->ringbuffer_gpadlhandle) { | |
| 937 | − ret = vmbus_teardown_gpadl(channel, | |
| 938 | − channel->ringbuffer_gpadlhandle); | |
| 963 | + else if (channel->ringbuffer_gpadlhandle.gpadl_handle) { | |
| 964 | + ret = vmbus_teardown_gpadl(channel, &channel->ringbuffer_gpadlhandle); | |
| 939 | 965 | if (ret) { |
| 940 | 966 | pr_err("Close failed: teardown gpadl return %d\n", ret); |
| 941 | 967 | /* |
| @@ -943,8 +969,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel) · 1 unmodified line | ||
| 943 | 969 | * it is perhaps better to leak memory. |
| 944 | 970 | */ |
| 945 | 971 | } |
| 946 | − | |
| 947 | − channel->ringbuffer_gpadlhandle = 0; | |
| 948 | 972 | } |
| 949 | 973 | |
| 950 | 974 | if (!ret) |
| @@ -1581,21 +1581,6 @@ cleanup: · 1580 unmodified lines | ||
| 1581 | 1581 | return ret; |
| 1582 | 1582 | } |
| 1583 | 1583 | |
| 1584 | −static void invoke_sc_cb(struct vmbus_channel *primary_channel) | |
| 1585 | −{ | |
| 1586 | − struct list_head *cur, *tmp; | |
| 1587 | − struct vmbus_channel *cur_channel; | |
| 1588 | − | |
| 1589 | − if (primary_channel->sc_creation_callback == NULL) | |
| 1590 | − return; | |
| 1591 | − | |
| 1592 | − list_for_each_safe(cur, tmp, &primary_channel->sc_list) { | |
| 1593 | − cur_channel = list_entry(cur, struct vmbus_channel, sc_list); | |
| 1594 | − | |
| 1595 | − primary_channel->sc_creation_callback(cur_channel); | |
| 1596 | − } | |
| 1597 | −} | |
| 1598 | − | |
| 1599 | 1584 | void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, |
| 1600 | 1585 | void (*sc_cr_cb)(struct vmbus_channel *new_sc)) |
| 1601 | 1586 | { |
| @@ -1603,25 +1588,6 @@ void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, · 1 unmodified line | ||
| 1603 | 1588 | } |
| 1604 | 1589 | EXPORT_SYMBOL_GPL(vmbus_set_sc_create_callback); |
| 1605 | 1590 | |
| 1606 | −bool vmbus_are_subchannels_present(struct vmbus_channel *primary) | |
| 1607 | −{ | |
| 1608 | − bool ret; | |
| 1609 | − | |
| 1610 | − ret = !list_empty(&primary->sc_list); | |
| 1611 | − | |
| 1612 | − if (ret) { | |
| 1613 | − /* | |
| 1614 | − * Invoke the callback on sub-channel creation. | |
| 1615 | − * This will present a uniform interface to the | |
| 1616 | − * clients. | |
| 1617 | − */ | |
| 1618 | − invoke_sc_cb(primary); | |
| 1619 | − } | |
| 1620 | − | |
| 1621 | − return ret; | |
| 1622 | −} | |
| 1623 | −EXPORT_SYMBOL_GPL(vmbus_are_subchannels_present); | |
| 1624 | − | |
| 1625 | 1591 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, |
| 1626 | 1592 | void (*chn_rescind_cb)(struct vmbus_channel *)) |
| 1627 | 1593 | { |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | #include <linux/hyperv.h> |
| 21 | 21 | #include <linux/export.h> |
| 22 | +#include <linux/io.h> | |
| 23 | +#include <linux/set_memory.h> | |
| 22 | 24 | #include <asm/mshyperv.h> |
| 23 | 25 | |
| 24 | 26 | #include "hyperv_vmbus.h" |
| @@ -102,8 +104,9 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) · 77 unmodified lines | ||
| 102 | 104 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; |
| 103 | 105 | } |
| 104 | 106 | |
| 105 | − msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); | |
| 106 | − msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); | |
| 107 | + msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0]; | |
| 108 | + msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1]; | |
| 109 | + | |
| 107 | 110 | msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU); |
| 108 | 111 | |
| 109 | 112 | /* |
| @@ -216,6 +219,65 @@ int vmbus_connect(void) · 106 unmodified lines | ||
| 216 | 219 | goto cleanup; |
| 217 | 220 | } |
| 218 | 221 | |
| 222 | + vmbus_connection.monitor_pages_original[0] | |
| 223 | + = vmbus_connection.monitor_pages[0]; | |
| 224 | + vmbus_connection.monitor_pages_original[1] | |
| 225 | + = vmbus_connection.monitor_pages[1]; | |
| 226 | + vmbus_connection.monitor_pages_pa[0] | |
| 227 | + = virt_to_phys(vmbus_connection.monitor_pages[0]); | |
| 228 | + vmbus_connection.monitor_pages_pa[1] | |
| 229 | + = virt_to_phys(vmbus_connection.monitor_pages[1]); | |
| 230 | + | |
| 231 | + if (hv_is_isolation_supported()) { | |
| 232 | + ret = set_memory_decrypted((unsigned long) | |
| 233 | + vmbus_connection.monitor_pages[0], | |
| 234 | + 1); | |
| 235 | + ret |= set_memory_decrypted((unsigned long) | |
| 236 | + vmbus_connection.monitor_pages[1], | |
| 237 | + 1); | |
| 238 | + if (ret) | |
| 239 | + goto cleanup; | |
| 240 | + | |
| 241 | + /* | |
| 242 | + * Isolation VM with AMD SNP needs to access monitor page via | |
| 243 | + * address space above shared gpa boundary. | |
| 244 | + */ | |
| 245 | + if (hv_isolation_type_snp()) { | |
| 246 | + vmbus_connection.monitor_pages_pa[0] += | |
| 247 | + ms_hyperv.shared_gpa_boundary; | |
| 248 | + vmbus_connection.monitor_pages_pa[1] += | |
| 249 | + ms_hyperv.shared_gpa_boundary; | |
| 250 | + | |
| 251 | + vmbus_connection.monitor_pages[0] | |
| 252 | + = memremap(vmbus_connection.monitor_pages_pa[0], | |
| 253 | + HV_HYP_PAGE_SIZE, | |
| 254 | + MEMREMAP_WB); | |
| 255 | + if (!vmbus_connection.monitor_pages[0]) { | |
| 256 | + ret = -ENOMEM; | |
| 257 | + goto cleanup; | |
| 258 | + } | |
| 259 | + | |
| 260 | + vmbus_connection.monitor_pages[1] | |
| 261 | + = memremap(vmbus_connection.monitor_pages_pa[1], | |
| 262 | + HV_HYP_PAGE_SIZE, | |
| 263 | + MEMREMAP_WB); | |
| 264 | + if (!vmbus_connection.monitor_pages[1]) { | |
| 265 | + ret = -ENOMEM; | |
| 266 | + goto cleanup; | |
| 267 | + } | |
| 268 | + } | |
| 269 | + | |
| 270 | + /* | |
| 271 | + * Set memory host visibility hvcall smears memory | |
| 272 | + * and so zero monitor pages here. | |
| 273 | + */ | |
| 274 | + memset(vmbus_connection.monitor_pages[0], 0x00, | |
| 275 | + HV_HYP_PAGE_SIZE); | |
| 276 | + memset(vmbus_connection.monitor_pages[1], 0x00, | |
| 277 | + HV_HYP_PAGE_SIZE); | |
| 278 | + | |
| 279 | + } | |
| 280 | + | |
| 219 | 281 | msginfo = kzalloc(sizeof(*msginfo) + |
| 220 | 282 | sizeof(struct vmbus_channel_initiate_contact), |
| 221 | 283 | GFP_KERNEL); |
| @@ -303,10 +365,31 @@ void vmbus_disconnect(void) · 81 unmodified lines | ||
| 303 | 365 | vmbus_connection.int_page = NULL; |
| 304 | 366 | } |
| 305 | 367 | |
| 306 | − hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); | |
| 307 | − hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); | |
| 308 | − vmbus_connection.monitor_pages[0] = NULL; | |
| 309 | − vmbus_connection.monitor_pages[1] = NULL; | |
| 368 | + if (hv_is_isolation_supported()) { | |
| 369 | + /* | |
| 370 | + * memunmap() checks input address is ioremap address or not | |
| 371 | + * inside. It doesn't unmap any thing in the non-SNP CVM and | |
| 372 | + * so not check CVM type here. | |
| 373 | + */ | |
| 374 | + memunmap(vmbus_connection.monitor_pages[0]); | |
| 375 | + memunmap(vmbus_connection.monitor_pages[1]); | |
| 376 | + | |
| 377 | + set_memory_encrypted((unsigned long) | |
| 378 | + vmbus_connection.monitor_pages_original[0], | |
| 379 | + 1); | |
| 380 | + set_memory_encrypted((unsigned long) | |
| 381 | + vmbus_connection.monitor_pages_original[1], | |
| 382 | + 1); | |
| 383 | + } | |
| 384 | + | |
| 385 | + hv_free_hyperv_page((unsigned long) | |
| 386 | + vmbus_connection.monitor_pages_original[0]); | |
| 387 | + hv_free_hyperv_page((unsigned long) | |
| 388 | + vmbus_connection.monitor_pages_original[1]); | |
| 389 | + vmbus_connection.monitor_pages_original[0] = | |
| 390 | + vmbus_connection.monitor_pages[0] = NULL; | |
| 391 | + vmbus_connection.monitor_pages_original[1] = | |
| 392 | + vmbus_connection.monitor_pages[1] = NULL; | |
| 310 | 393 | } |
| 311 | 394 | |
| 312 | 395 | /* |
| @@ -447,6 +530,10 @@ void vmbus_set_event(struct vmbus_channel *channel) · 134 unmodified lines | ||
| 447 | 530 | |
| 448 | 531 | ++channel->sig_events; |
| 449 | 532 | |
| 450 | − hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event); | |
| 533 | + if (hv_isolation_type_snp()) | |
| 534 | + hv_ghcb_hypercall(HVCALL_SIGNAL_EVENT, &channel->sig_event, | |
| 535 | + NULL, sizeof(channel->sig_event)); | |
| 536 | + else | |
| 537 | + hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event); | |
| 451 | 538 | } |
| 452 | 539 | EXPORT_SYMBOL_GPL(vmbus_set_event); |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 10 | 10 | |
| 11 | +#include <linux/io.h> | |
| 11 | 12 | #include <linux/kernel.h> |
| 12 | 13 | #include <linux/mm.h> |
| 13 | 14 | #include <linux/slab.h> |
| @@ -97,7 +98,13 @@ int hv_post_message(union hv_connection_id connection_id, · 83 unmodified lines | ||
| 97 | 98 | aligned_msg->payload_size = payload_size; |
| 98 | 99 | memcpy((void *)aligned_msg->payload, payload, payload_size); |
| 99 | 100 | |
| 100 | − status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); | |
| 101 | + if (hv_isolation_type_snp()) | |
| 102 | + status = hv_ghcb_hypercall(HVCALL_POST_MESSAGE, | |
| 103 | + (void *)aligned_msg, NULL, | |
| 104 | + sizeof(*aligned_msg)); | |
| 105 | + else | |
| 106 | + status = hv_do_hypercall(HVCALL_POST_MESSAGE, | |
| 107 | + aligned_msg, NULL); | |
| 101 | 108 | |
| 102 | 109 | /* Preemption must remain disabled until after the hypercall |
| 103 | 110 | * so some other thread can't get scheduled onto this cpu and |
| @@ -136,17 +143,24 @@ int hv_synic_alloc(void) · 32 unmodified lines | ||
| 136 | 143 | tasklet_init(&hv_cpu->msg_dpc, |
| 137 | 144 | vmbus_on_msg_dpc, (unsigned long) hv_cpu); |
| 138 | 145 | |
| 139 | − hv_cpu->synic_message_page = | |
| 140 | − (void *)get_zeroed_page(GFP_ATOMIC); | |
| 141 | − if (hv_cpu->synic_message_page == NULL) { | |
| 142 | − pr_err("Unable to allocate SYNIC message page\n"); | |
| 143 | − goto err; | |
| 144 | − } | |
| 146 | + /* | |
| 147 | + * Synic message and event pages are allocated by paravisor. | |
| 148 | + * Skip these pages allocation here. | |
| 149 | + */ | |
| 150 | + if (!hv_isolation_type_snp()) { | |
| 151 | + hv_cpu->synic_message_page = | |
| 152 | + (void *)get_zeroed_page(GFP_ATOMIC); | |
| 153 | + if (hv_cpu->synic_message_page == NULL) { | |
| 154 | + pr_err("Unable to allocate SYNIC message page\n"); | |
| 155 | + goto err; | |
| 156 | + } | |
| 145 | 157 | |
| 146 | − hv_cpu->synic_event_page = (void *)get_zeroed_page(GFP_ATOMIC); | |
| 147 | − if (hv_cpu->synic_event_page == NULL) { | |
| 148 | − pr_err("Unable to allocate SYNIC event page\n"); | |
| 149 | − goto err; | |
| 158 | + hv_cpu->synic_event_page = | |
| 159 | + (void *)get_zeroed_page(GFP_ATOMIC); | |
| 160 | + if (hv_cpu->synic_event_page == NULL) { | |
| 161 | + pr_err("Unable to allocate SYNIC event page\n"); | |
| 162 | + goto err; | |
| 163 | + } | |
| 150 | 164 | } |
| 151 | 165 | |
| 152 | 166 | hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); |
| @@ -201,16 +215,35 @@ void hv_synic_enable_regs(unsigned int cpu) · 48 unmodified lines | ||
| 201 | 215 | /* Setup the Synic's message page */ |
| 202 | 216 | simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); |
| 203 | 217 | simp.simp_enabled = 1; |
| 204 | − simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) | |
| 205 | − >> HV_HYP_PAGE_SHIFT; | |
| 218 | + | |
| 219 | + if (hv_isolation_type_snp()) { | |
| 220 | + hv_cpu->synic_message_page | |
| 221 | + = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT, | |
| 222 | + HV_HYP_PAGE_SIZE, MEMREMAP_WB); | |
| 223 | + if (!hv_cpu->synic_message_page) | |
| 224 | + pr_err("Fail to map syinc message page.\n"); | |
| 225 | + } else { | |
| 226 | + simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) | |
| 227 | + >> HV_HYP_PAGE_SHIFT; | |
| 228 | + } | |
| 206 | 229 | |
| 207 | 230 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); |
| 208 | 231 | |
| 209 | 232 | /* Setup the Synic's event page */ |
| 210 | 233 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); |
| 211 | 234 | siefp.siefp_enabled = 1; |
| 212 | − siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) | |
| 213 | − >> HV_HYP_PAGE_SHIFT; | |
| 235 | + | |
| 236 | + if (hv_isolation_type_snp()) { | |
| 237 | + hv_cpu->synic_event_page = | |
| 238 | + memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT, | |
| 239 | + HV_HYP_PAGE_SIZE, MEMREMAP_WB); | |
| 240 | + | |
| 241 | + if (!hv_cpu->synic_event_page) | |
| 242 | + pr_err("Fail to map syinc event page.\n"); | |
| 243 | + } else { | |
| 244 | + siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) | |
| 245 | + >> HV_HYP_PAGE_SHIFT; | |
| 246 | + } | |
| 214 | 247 | |
| 215 | 248 | hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); |
| 216 | 249 | |
| @@ -257,6 +290,8 @@ int hv_synic_init(unsigned int cpu) · 40 unmodified lines | ||
| 257 | 290 | */ |
| 258 | 291 | void hv_synic_disable_regs(unsigned int cpu) |
| 259 | 292 | { |
| 293 | + struct hv_per_cpu_context *hv_cpu | |
| 294 | + = per_cpu_ptr(hv_context.cpu_context, cpu); | |
| 260 | 295 | union hv_synic_sint shared_sint; |
| 261 | 296 | union hv_synic_simp simp; |
| 262 | 297 | union hv_synic_siefp siefp; |
| @@ -273,14 +308,27 @@ void hv_synic_disable_regs(unsigned int cpu) · 10 unmodified lines | ||
| 273 | 308 | shared_sint.as_uint64); |
| 274 | 309 | |
| 275 | 310 | simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); |
| 311 | + /* | |
| 312 | + * In Isolation VM, sim and sief pages are allocated by | |
| 313 | + * paravisor. These pages also will be used by kdump | |
| 314 | + * kernel. So just reset enable bit here and keep page | |
| 315 | + * addresses. | |
| 316 | + */ | |
| 276 | 317 | simp.simp_enabled = 0; |
| 277 | − simp.base_simp_gpa = 0; | |
| 318 | + if (hv_isolation_type_snp()) | |
| 319 | + memunmap(hv_cpu->synic_message_page); | |
| 320 | + else | |
| 321 | + simp.base_simp_gpa = 0; | |
| 278 | 322 | |
| 279 | 323 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); |
| 280 | 324 | |
| 281 | 325 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); |
| 282 | 326 | siefp.siefp_enabled = 0; |
| 283 | − siefp.base_siefp_gpa = 0; | |
| 327 | + | |
| 328 | + if (hv_isolation_type_snp()) | |
| 329 | + memunmap(hv_cpu->synic_event_page); | |
| 330 | + else | |
| 331 | + siefp.base_siefp_gpa = 0; | |
| 284 | 332 | |
| 285 | 333 | hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); |
| 286 | 334 | |
| @@ -249,6 +249,12 @@ bool __weak hv_is_isolation_supported(void) · 248 unmodified lines | ||
| 249 | 249 | } |
| 250 | 250 | EXPORT_SYMBOL_GPL(hv_is_isolation_supported); |
| 251 | 251 | |
| 252 | +bool __weak hv_isolation_type_snp(void) | |
| 253 | +{ | |
| 254 | + return false; | |
| 255 | +} | |
| 256 | +EXPORT_SYMBOL_GPL(hv_isolation_type_snp); | |
| 257 | + | |
| 252 | 258 | void __weak hv_setup_vmbus_handler(void (*handler)(void)) |
| 253 | 259 | { |
| 254 | 260 | } |
| @@ -283,3 +289,9 @@ void __weak hyperv_cleanup(void) · 28 unmodified lines | ||
| 283 | 289 | { |
| 284 | 290 | } |
| 285 | 291 | EXPORT_SYMBOL_GPL(hyperv_cleanup); |
| 292 | + | |
| 293 | +u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size) | |
| 294 | +{ | |
| 295 | + return HV_STATUS_INVALID_PARAMETER; | |
| 296 | +} | |
| 297 | +EXPORT_SYMBOL_GPL(hv_ghcb_hypercall); | |
| @@ -241,6 +241,8 @@ struct vmbus_connection { · 240 unmodified lines | ||
| 241 | 241 | * is child->parent notification |
| 242 | 242 | */ |
| 243 | 243 | struct hv_monitor_page *monitor_pages[2]; |
| 244 | + void *monitor_pages_original[2]; | |
| 245 | + phys_addr_t monitor_pages_pa[2]; | |
| 244 | 246 | struct list_head chn_msg_list; |
| 245 | 247 | spinlock_t channelmsg_lock; |
| 246 | 248 | |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/vmalloc.h> |
| 18 | 18 | #include <linux/slab.h> |
| 19 | 19 | #include <linux/prefetch.h> |
| 20 | +#include <linux/io.h> | |
| 21 | +#include <asm/mshyperv.h> | |
| 20 | 22 | |
| 21 | 23 | #include "hyperv_vmbus.h" |
| 22 | 24 | |
| @@ -183,8 +185,10 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel) · 160 unmodified lines | ||
| 183 | 185 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
| 184 | 186 | struct page *pages, u32 page_cnt, u32 max_pkt_size) |
| 185 | 187 | { |
| 186 | − int i; | |
| 187 | 188 | struct page **pages_wraparound; |
| 189 | + unsigned long *pfns_wraparound; | |
| 190 | + u64 pfn; | |
| 191 | + int i; | |
| 188 | 192 | |
| 189 | 193 | BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); |
| 190 | 194 | |
| @@ -192,23 +196,50 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, · 1 unmodified line | ||
| 192 | 196 | * First page holds struct hv_ring_buffer, do wraparound mapping for |
| 193 | 197 | * the rest. |
| 194 | 198 | */ |
| 195 | − pages_wraparound = kcalloc(page_cnt * 2 - 1, sizeof(struct page *), | |
| 196 | − GFP_KERNEL); | |
| 197 | − if (!pages_wraparound) | |
| 198 | − return -ENOMEM; | |
| 199 | + if (hv_isolation_type_snp()) { | |
| 200 | + pfn = page_to_pfn(pages) + | |
| 201 | + PFN_DOWN(ms_hyperv.shared_gpa_boundary); | |
| 202 | + | |
| 203 | + pfns_wraparound = kcalloc(page_cnt * 2 - 1, | |
| 204 | + sizeof(unsigned long), GFP_KERNEL); | |
| 205 | + if (!pfns_wraparound) | |
| 206 | + return -ENOMEM; | |
| 199 | 207 | |
| 200 | − pages_wraparound[0] = pages; | |
| 201 | − for (i = 0; i < 2 * (page_cnt - 1); i++) | |
| 202 | − pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1]; | |
| 208 | + pfns_wraparound[0] = pfn; | |
| 209 | + for (i = 0; i < 2 * (page_cnt - 1); i++) | |
| 210 | + pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1; | |
| 203 | 211 | |
| 204 | − ring_info->ring_buffer = (struct hv_ring_buffer *) | |
| 205 | − vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL); | |
| 212 | + ring_info->ring_buffer = (struct hv_ring_buffer *) | |
| 213 | + vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, | |
| 214 | + PAGE_KERNEL); | |
| 215 | + kfree(pfns_wraparound); | |
| 206 | 216 | |
| 207 | − kfree(pages_wraparound); | |
| 217 | + if (!ring_info->ring_buffer) | |
| 218 | + return -ENOMEM; | |
| 208 | 219 | |
| 220 | + /* Zero ring buffer after setting memory host visibility. */ | |
| 221 | + memset(ring_info->ring_buffer, 0x00, PAGE_SIZE * page_cnt); | |
| 222 | + } else { | |
| 223 | + pages_wraparound = kcalloc(page_cnt * 2 - 1, | |
| 224 | + sizeof(struct page *), | |
| 225 | + GFP_KERNEL); | |
| 226 | + if (!pages_wraparound) | |
| 227 | + return -ENOMEM; | |
| 228 | + | |
| 229 | + pages_wraparound[0] = pages; | |
| 230 | + for (i = 0; i < 2 * (page_cnt - 1); i++) | |
| 231 | + pages_wraparound[i + 1] = | |
| 232 | + &pages[i % (page_cnt - 1) + 1]; | |
| 233 | + | |
| 234 | + ring_info->ring_buffer = (struct hv_ring_buffer *) | |
| 235 | + vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, | |
| 236 | + PAGE_KERNEL); | |
| 237 | + | |
| 238 | + kfree(pages_wraparound); | |
| 239 | + if (!ring_info->ring_buffer) | |
| 240 | + return -ENOMEM; | |
| 241 | + } | |
| 209 | 242 | |
| 210 | − if (!ring_info->ring_buffer) | |
| 211 | − return -ENOMEM; | |
| 212 | 243 | |
| 213 | 244 | ring_info->ring_buffer->read_index = |
| 214 | 245 | ring_info->ring_buffer->write_index = 0; |
| @@ -1075,14 +1075,15 @@ struct netvsc_device { · 1074 unmodified lines | ||
| 1075 | 1075 | /* Receive buffer allocated by us but manages by NetVSP */ |
| 1076 | 1076 | void *recv_buf; |
| 1077 | 1077 | u32 recv_buf_size; /* allocated bytes */ |
| 1078 | − u32 recv_buf_gpadl_handle; | |
| 1078 | + struct vmbus_gpadl recv_buf_gpadl_handle; | |
| 1079 | 1079 | u32 recv_section_cnt; |
| 1080 | 1080 | u32 recv_section_size; |
| 1081 | 1081 | u32 recv_completion_cnt; |
| 1082 | 1082 | |
| 1083 | 1083 | /* Send buffer allocated by us */ |
| 1084 | 1084 | void *send_buf; |
| 1085 | − u32 send_buf_gpadl_handle; | |
| 1085 | + u32 send_buf_size; | |
| 1086 | + struct vmbus_gpadl send_buf_gpadl_handle; | |
| 1086 | 1087 | u32 send_section_cnt; |
| 1087 | 1088 | u32 send_section_size; |
| 1088 | 1089 | unsigned long *send_section_map; |
| @@ -278,9 +278,9 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device, · 277 unmodified lines | ||
| 278 | 278 | { |
| 279 | 279 | int ret; |
| 280 | 280 | |
| 281 | − if (net_device->recv_buf_gpadl_handle) { | |
| 281 | + if (net_device->recv_buf_gpadl_handle.gpadl_handle) { | |
| 282 | 282 | ret = vmbus_teardown_gpadl(device->channel, |
| 283 | − net_device->recv_buf_gpadl_handle); | |
| 283 | + &net_device->recv_buf_gpadl_handle); | |
| 284 | 284 | |
| 285 | 285 | /* If we failed here, we might as well return and have a leak |
| 286 | 286 | * rather than continue and a bugchk |
| @@ -290,7 +290,6 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device, · 3 unmodified lines | ||
| 290 | 290 | "unable to teardown receive buffer's gpadl\n"); |
| 291 | 291 | return; |
| 292 | 292 | } |
| 293 | − net_device->recv_buf_gpadl_handle = 0; | |
| 294 | 293 | } |
| 295 | 294 | } |
| 296 | 295 | |
| @@ -300,9 +299,9 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device, · 3 unmodified lines | ||
| 300 | 299 | { |
| 301 | 300 | int ret; |
| 302 | 301 | |
| 303 | − if (net_device->send_buf_gpadl_handle) { | |
| 302 | + if (net_device->send_buf_gpadl_handle.gpadl_handle) { | |
| 304 | 303 | ret = vmbus_teardown_gpadl(device->channel, |
| 305 | − net_device->send_buf_gpadl_handle); | |
| 304 | + &net_device->send_buf_gpadl_handle); | |
| 306 | 305 | |
| 307 | 306 | /* If we failed here, we might as well return and have a leak |
| 308 | 307 | * rather than continue and a bugchk |
| @@ -312,7 +311,6 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device, · 3 unmodified lines | ||
| 312 | 311 | "unable to teardown send buffer's gpadl\n"); |
| 313 | 312 | return; |
| 314 | 313 | } |
| 315 | − net_device->send_buf_gpadl_handle = 0; | |
| 316 | 314 | } |
| 317 | 315 | } |
| 318 | 316 | |
| @@ -380,7 +378,7 @@ static int netvsc_init_buf(struct hv_device *device, · 61 unmodified lines | ||
| 380 | 378 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| 381 | 379 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; |
| 382 | 380 | init_packet->msg.v1_msg.send_recv_buf. |
| 383 | − gpadl_handle = net_device->recv_buf_gpadl_handle; | |
| 381 | + gpadl_handle = net_device->recv_buf_gpadl_handle.gpadl_handle; | |
| 384 | 382 | init_packet->msg.v1_msg. |
| 385 | 383 | send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; |
| 386 | 384 | |
| @@ -463,6 +461,7 @@ static int netvsc_init_buf(struct hv_device *device, · 76 unmodified lines | ||
| 463 | 461 | ret = -ENOMEM; |
| 464 | 462 | goto cleanup; |
| 465 | 463 | } |
| 464 | + net_device->send_buf_size = buf_size; | |
| 466 | 465 | |
| 467 | 466 | /* Establish the gpadl handle for this buffer on this |
| 468 | 467 | * channel. Note: This call uses the vmbus connection rather |
| @@ -482,7 +481,7 @@ static int netvsc_init_buf(struct hv_device *device, · 13 unmodified lines | ||
| 482 | 481 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| 483 | 482 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; |
| 484 | 483 | init_packet->msg.v1_msg.send_send_buf.gpadl_handle = |
| 485 | − net_device->send_buf_gpadl_handle; | |
| 484 | + net_device->send_buf_gpadl_handle.gpadl_handle; | |
| 486 | 485 | init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; |
| 487 | 486 | |
| 488 | 487 | trace_nvsp_send(ndev, init_packet); |
| @@ -58,11 +58,11 @@ struct hv_uio_private_data { · 57 unmodified lines | ||
| 58 | 58 | atomic_t refcnt; |
| 59 | 59 | |
| 60 | 60 | void *recv_buf; |
| 61 | − u32 recv_gpadl; | |
| 61 | + struct vmbus_gpadl recv_gpadl; | |
| 62 | 62 | char recv_name[32]; /* "recv_4294967295" */ |
| 63 | 63 | |
| 64 | 64 | void *send_buf; |
| 65 | − u32 send_gpadl; | |
| 65 | + struct vmbus_gpadl send_gpadl; | |
| 66 | 66 | char send_name[32]; |
| 67 | 67 | }; |
| 68 | 68 | |
| @@ -179,15 +179,13 @@ hv_uio_new_channel(struct vmbus_channel *new_sc) · 110 unmodified lines | ||
| 179 | 179 | static void |
| 180 | 180 | hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) |
| 181 | 181 | { |
| 182 | − if (pdata->send_gpadl) { | |
| 183 | − vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl); | |
| 184 | − pdata->send_gpadl = 0; | |
| 182 | + if (pdata->send_gpadl.gpadl_handle) { | |
| 183 | + vmbus_teardown_gpadl(dev->channel, &pdata->send_gpadl); | |
| 185 | 184 | vfree(pdata->send_buf); |
| 186 | 185 | } |
| 187 | 186 | |
| 188 | − if (pdata->recv_gpadl) { | |
| 189 | − vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl); | |
| 190 | − pdata->recv_gpadl = 0; | |
| 187 | + if (pdata->recv_gpadl.gpadl_handle) { | |
| 188 | + vmbus_teardown_gpadl(dev->channel, &pdata->recv_gpadl); | |
| 191 | 189 | vfree(pdata->recv_buf); |
| 192 | 190 | } |
| 193 | 191 | } |
| @@ -303,7 +301,7 @@ hv_uio_probe(struct hv_device *dev, · 109 unmodified lines | ||
| 303 | 301 | |
| 304 | 302 | /* put Global Physical Address Label in name */ |
| 305 | 303 | snprintf(pdata->recv_name, sizeof(pdata->recv_name), |
| 306 | − "recv:%u", pdata->recv_gpadl); | |
| 304 | + "recv:%u", pdata->recv_gpadl.gpadl_handle); | |
| 307 | 305 | pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; |
| 308 | 306 | pdata->info.mem[RECV_BUF_MAP].addr |
| 309 | 307 | = (uintptr_t)pdata->recv_buf; |
| @@ -324,7 +322,7 @@ hv_uio_probe(struct hv_device *dev, · 14 unmodified lines | ||
| 324 | 322 | } |
| 325 | 323 | |
| 326 | 324 | snprintf(pdata->send_name, sizeof(pdata->send_name), |
| 327 | − "send:%u", pdata->send_gpadl); | |
| 325 | + "send:%u", pdata->send_gpadl.gpadl_handle); | |
| 328 | 326 | pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; |
| 329 | 327 | pdata->info.mem[SEND_BUF_MAP].addr |
| 330 | 328 | = (uintptr_t)pdata->send_buf; |
| @@ -158,6 +158,7 @@ struct ms_hyperv_tsc_page { · 157 unmodified lines | ||
| 158 | 158 | #define HVCALL_RETARGET_INTERRUPT 0x007e |
| 159 | 159 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af |
| 160 | 160 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 |
| 161 | +#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db | |
| 161 | 162 | |
| 162 | 163 | /* Extended hypercalls */ |
| 163 | 164 | #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 |
| @@ -35,7 +35,17 @@ struct ms_hyperv_info { · 34 unmodified lines | ||
| 35 | 35 | u32 max_vp_index; |
| 36 | 36 | u32 max_lp_index; |
| 37 | 37 | u32 isolation_config_a; |
| 38 | − u32 isolation_config_b; | |
| 38 | + union { | |
| 39 | + u32 isolation_config_b; | |
| 40 | + struct { | |
| 41 | + u32 cvm_type : 4; | |
| 42 | + u32 reserved1 : 1; | |
| 43 | + u32 shared_gpa_boundary_active : 1; | |
| 44 | + u32 shared_gpa_boundary_bits : 6; | |
| 45 | + u32 reserved2 : 20; | |
| 46 | + }; | |
| 47 | + }; | |
| 48 | + u64 shared_gpa_boundary; | |
| 39 | 49 | }; |
| 40 | 50 | extern struct ms_hyperv_info ms_hyperv; |
| 41 | 51 | |
| @@ -44,6 +54,7 @@ extern void __percpu **hyperv_pcpu_output_arg; · 2 unmodified lines | ||
| 44 | 54 | |
| 45 | 55 | extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); |
| 46 | 56 | extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); |
| 57 | +extern bool hv_isolation_type_snp(void); | |
| 47 | 58 | |
| 48 | 59 | /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ |
| 49 | 60 | static inline int hv_result(u64 status) |
| @@ -254,12 +265,19 @@ bool hv_is_hyperv_initialized(void); · 204 unmodified lines | ||
| 254 | 265 | bool hv_is_hibernation_supported(void); |
| 255 | 266 | enum hv_isolation_type hv_get_isolation_type(void); |
| 256 | 267 | bool hv_is_isolation_supported(void); |
| 268 | +bool hv_isolation_type_snp(void); | |
| 269 | +u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); | |
| 257 | 270 | void hyperv_cleanup(void); |
| 258 | 271 | bool hv_query_ext_cap(u64 cap_query); |
| 259 | 272 | #else /* CONFIG_HYPERV */ |
| 260 | 273 | static inline bool hv_is_hyperv_initialized(void) { return false; } |
| 261 | 274 | static inline bool hv_is_hibernation_supported(void) { return false; } |
| 262 | 275 | static inline void hyperv_cleanup(void) {} |
| 276 | +static inline bool hv_is_isolation_supported(void) { return false; } | |
| 277 | +static inline enum hv_isolation_type hv_get_isolation_type(void) | |
| 278 | +{ | |
| 279 | + return HV_ISOLATION_TYPE_NONE; | |
| 280 | +} | |
| 263 | 281 | #endif /* CONFIG_HYPERV */ |
| 264 | 282 | |
| 265 | 283 | #endif |
| @@ -803,6 +803,12 @@ struct vmbus_device { · 802 unmodified lines | ||
| 803 | 803 | |
| 804 | 804 | #define VMBUS_DEFAULT_MAX_PKT_SIZE 4096 |
| 805 | 805 | |
| 806 | +struct vmbus_gpadl { | |
| 807 | + u32 gpadl_handle; | |
| 808 | + u32 size; | |
| 809 | + void *buffer; | |
| 810 | +}; | |
| 811 | + | |
| 806 | 812 | struct vmbus_channel { |
| 807 | 813 | struct list_head listentry; |
| 808 | 814 | |
| @@ -822,7 +828,7 @@ struct vmbus_channel { · 13 unmodified lines | ||
| 822 | 828 | bool rescind_ref; /* got rescind msg, got channel reference */ |
| 823 | 829 | struct completion rescind_event; |
| 824 | 830 | |
| 825 | − u32 ringbuffer_gpadlhandle; | |
| 831 | + struct vmbus_gpadl ringbuffer_gpadlhandle; | |
| 826 | 832 | |
| 827 | 833 | /* Allocated memory for ring buffer */ |
| 828 | 834 | struct page *ringbuffer_page; |
| @@ -1100,19 +1106,6 @@ void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, · 271 unmodified lines | ||
| 1100 | 1106 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, |
| 1101 | 1107 | void (*chn_rescind_cb)(struct vmbus_channel *)); |
| 1102 | 1108 | |
| 1103 | −/* | |
| 1104 | − * Check if sub-channels have already been offerred. This API will be useful | |
| 1105 | − * when the driver is unloaded after establishing sub-channels. In this case, | |
| 1106 | − * when the driver is re-loaded, the driver would have to check if the | |
| 1107 | − * subchannels have already been established before attempting to request | |
| 1108 | − * the creation of sub-channels. | |
| 1109 | − * This function returns TRUE to indicate that subchannels have already been | |
| 1110 | − * created. | |
| 1111 | − * This function should be invoked after setting the callback function for | |
| 1112 | − * sub-channel creation. | |
| 1113 | − */ | |
| 1114 | −bool vmbus_are_subchannels_present(struct vmbus_channel *primary); | |
| 1115 | − | |
| 1116 | 1109 | /* The format must be the same as struct vmdata_gpa_direct */ |
| 1117 | 1110 | struct vmbus_channel_packet_page_buffer { |
| 1118 | 1111 | u16 type; |
| @@ -1192,10 +1185,10 @@ extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, · 73 unmodified lines | ||
| 1192 | 1185 | extern int vmbus_establish_gpadl(struct vmbus_channel *channel, |
| 1193 | 1186 | void *kbuffer, |
| 1194 | 1187 | u32 size, |
| 1195 | − u32 *gpadl_handle); | |
| 1188 | + struct vmbus_gpadl *gpadl); | |
| 1196 | 1189 | |
| 1197 | 1190 | extern int vmbus_teardown_gpadl(struct vmbus_channel *channel, |
| 1198 | − u32 gpadl_handle); | |
| 1191 | + struct vmbus_gpadl *gpadl); | |
| 1199 | 1192 | |
| 1200 | 1193 | void vmbus_reset_channel_cb(struct vmbus_channel *channel); |
| 1201 | 1194 | |