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 | # SPDX-License-Identifier: GPL-2.0-only | 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 | obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o | 3 | obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o |
| 4 | 4 | ||
| 5 | ifdef CONFIG_X86_64 | 5 | ifdef CONFIG_X86_64 |
| @@ -36,12 +36,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id); · 35 unmodified lines | |||
| 36 | void *hv_hypercall_pg; | 36 | void *hv_hypercall_pg; |
| 37 | EXPORT_SYMBOL_GPL(hv_hypercall_pg); | 37 | EXPORT_SYMBOL_GPL(hv_hypercall_pg); |
| 38 | 38 | ||
| 39 | union hv_ghcb __percpu **hv_ghcb_pg; | ||
| 40 | |||
| 39 | /* Storage to save the hypercall page temporarily for hibernation */ | 41 | /* Storage to save the hypercall page temporarily for hibernation */ |
| 40 | static void *hv_hypercall_pg_saved; | 42 | static void *hv_hypercall_pg_saved; |
| 41 | 43 | ||
| 42 | struct hv_vp_assist_page **hv_vp_assist_page; | 44 | struct hv_vp_assist_page **hv_vp_assist_page; |
| 43 | EXPORT_SYMBOL_GPL(hv_vp_assist_page); | 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 | static int hv_cpu_init(unsigned int cpu) | 75 | static int hv_cpu_init(unsigned int cpu) |
| 46 | { | 76 | { |
| 47 | union hv_vp_assist_msr_contents msr = { 0 }; | 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 | static void (*hv_reenlightenment_cb)(void); | 121 | static void (*hv_reenlightenment_cb)(void); |
| @@ -139,7 +169,6 @@ void set_hv_tscchange_cb(void (*cb)(void)) · 47 unmodified lines | |||
| 139 | struct hv_reenlightenment_control re_ctrl = { | 169 | struct hv_reenlightenment_control re_ctrl = { |
| 140 | .vector = HYPERV_REENLIGHTENMENT_VECTOR, | 170 | .vector = HYPERV_REENLIGHTENMENT_VECTOR, |
| 141 | .enabled = 1, | 171 | .enabled = 1, |
| 142 | .target_vp = hv_vp_index[smp_processor_id()] | ||
| 143 | }; | 172 | }; |
| 144 | struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; | 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 | /* Make sure callback is registered before we write to MSRs */ | 182 | /* Make sure callback is registered before we write to MSRs */ |
| 154 | wmb(); | 183 | wmb(); |
| 155 | 184 | ||
| 185 | re_ctrl.target_vp = hv_vp_index[get_cpu()]; | ||
| 186 | |||
| 156 | wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); | 187 | wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); |
| 157 | wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); | 188 | wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); |
| 189 | |||
| 190 | put_cpu(); | ||
| 158 | } | 191 | } |
| 159 | EXPORT_SYMBOL_GPL(set_hv_tscchange_cb); | 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 | struct hv_reenlightenment_control re_ctrl; | 211 | struct hv_reenlightenment_control re_ctrl; |
| 179 | unsigned int new_cpu; | 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 | hv_common_cpu_die(cpu); | 222 | hv_common_cpu_die(cpu); |
| 182 | 223 | ||
| @@ -366,10 +407,16 @@ void __init hyperv_init(void) · 183 unmodified lines | |||
| 366 | goto common_free; | 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 | cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online", | 416 | cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online", |
| 370 | hv_cpu_init, hv_cpu_die); | 417 | hv_cpu_init, hv_cpu_die); |
| 371 | if (cpuhp < 0) | 418 | if (cpuhp < 0) |
| 372 | goto free_vp_assist_page; | 419 | goto free_ghcb_page; |
| 373 | 420 | ||
| 374 | /* | 421 | /* |
| 375 | * Setup the hypercall page and enable hypercalls. | 422 | * Setup the hypercall page and enable hypercalls. |
| @@ -379,14 +426,15 @@ void __init hyperv_init(void) · 3 unmodified lines | |||
| 379 | guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); | 426 | guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); |
| 380 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); | 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 | hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, | 432 | hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, |
| 383 | VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, | 433 | VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, |
| 384 | VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, | 434 | VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, |
| 385 | __builtin_return_address(0)); | 435 | __builtin_return_address(0)); |
| 386 | if (hv_hypercall_pg == NULL) { | 436 | if (hv_hypercall_pg == NULL) |
| 387 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | 437 | goto clean_guest_os_id; |
| 388 | goto remove_cpuhp_state; | ||
| 389 | } | ||
| 390 | 438 | ||
| 391 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | 439 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); |
| 392 | hypercall_msr.enable = 1; | 440 | hypercall_msr.enable = 1; |
| @@ -456,8 +504,12 @@ void __init hyperv_init(void) · 63 unmodified lines | |||
| 456 | hv_query_ext_cap(0); | 504 | hv_query_ext_cap(0); |
| 457 | return; | 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 | cpuhp_remove_state(cpuhp); | 510 | cpuhp_remove_state(cpuhp); |
| 511 | free_ghcb_page: | ||
| 512 | free_percpu(hv_ghcb_pg); | ||
| 461 | free_vp_assist_page: | 513 | free_vp_assist_page: |
| 462 | kfree(hv_vp_assist_page); | 514 | kfree(hv_vp_assist_page); |
| 463 | hv_vp_assist_page = NULL; | 515 | hv_vp_assist_page = NULL; |
| @@ -476,6 +528,7 @@ void hyperv_cleanup(void) · 12 unmodified lines | |||
| 476 | 528 | ||
| 477 | /* Reset our OS id */ | 529 | /* Reset our OS id */ |
| 478 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | 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 | * Reset hypercall page reference before reset the page, | 534 | * Reset hypercall page reference before reset the page, |
| @@ -546,16 +599,3 @@ bool hv_is_hyperv_initialized(void) · 64 unmodified lines | |||
| 546 | return hypercall_msr.enable; | 599 | return hypercall_msr.enable; |
| 547 | } | 600 | } |
| 548 | EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized); | 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 | #define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT | 276 | #define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT |
| 277 | #define HV_X64_MSR_REFERENCE_TSC HV_REGISTER_REFERENCE_TSC | 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 | * Declare the MSR used to setup pages used to communicate with the hypervisor. | 297 | * Declare the MSR used to setup pages used to communicate with the hypervisor. |
| 281 | */ | 298 | */ |
| @@ -11,23 +11,14 @@ · 10 unmodified lines | |||
| 11 | #include <asm/paravirt.h> | 11 | #include <asm/paravirt.h> |
| 12 | #include <asm/mshyperv.h> | 12 | #include <asm/mshyperv.h> |
| 13 | 13 | ||
| 14 | union hv_ghcb; | ||
| 15 | |||
| 16 | DECLARE_STATIC_KEY_FALSE(isolation_type_snp); | ||
| 17 | |||
| 14 | typedef int (*hyperv_fill_flush_list_func)( | 18 | typedef int (*hyperv_fill_flush_list_func)( |
| 15 | struct hv_guest_mapping_flush_list *flush, | 19 | struct hv_guest_mapping_flush_list *flush, |
| 16 | void *data); | 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 | #define hv_get_raw_timer() rdtsc_ordered() | 22 | #define hv_get_raw_timer() rdtsc_ordered() |
| 32 | 23 | ||
| 33 | void hyperv_vector_handler(struct pt_regs *regs); | 24 | void hyperv_vector_handler(struct pt_regs *regs); |
| @@ -39,6 +30,8 @@ extern void *hv_hypercall_pg; · 5 unmodified lines | |||
| 39 | 30 | ||
| 40 | extern u64 hv_current_partition_id; | 31 | extern u64 hv_current_partition_id; |
| 41 | 32 | ||
| 33 | extern union hv_ghcb __percpu **hv_ghcb_pg; | ||
| 34 | |||
| 42 | int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); | 35 | int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); |
| 43 | int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); | 36 | int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); |
| 44 | int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags); | 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 | int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, | 181 | int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, |
| 189 | struct hv_interrupt_entry *entry); | 182 | struct hv_interrupt_entry *entry); |
| 190 | int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); | 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 | #else /* CONFIG_HYPERV */ | 229 | #else /* CONFIG_HYPERV */ |
| 193 | static inline void hyperv_init(void) {} | 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 | return -1; | 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 | #endif /* CONFIG_HYPERV */ | 252 | #endif /* CONFIG_HYPERV */ |
| 209 | 253 | ||
| 210 | 254 | ||
| @@ -313,9 +313,14 @@ static void __init ms_hyperv_init_platform(void) · 312 unmodified lines | |||
| 313 | if (ms_hyperv.priv_high & HV_ISOLATION) { | 313 | if (ms_hyperv.priv_high & HV_ISOLATION) { |
| 314 | ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); | 314 | ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG); |
| 315 | ms_hyperv.isolation_config_b = cpuid_ebx(HYPERV_CPUID_ISOLATION_CONFIG); | 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 | pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", | 319 | pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", |
| 318 | ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); | 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 | if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { | 326 | if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { |
| @@ -30,6 +30,8 @@ · 29 unmodified lines | |||
| 30 | #include <asm/proto.h> | 30 | #include <asm/proto.h> |
| 31 | #include <asm/memtype.h> | 31 | #include <asm/memtype.h> |
| 32 | #include <asm/set_memory.h> | 32 | #include <asm/set_memory.h> |
| 33 | #include <asm/hyperv-tlfs.h> | ||
| 34 | #include <asm/mshyperv.h> | ||
| 33 | 35 | ||
| 34 | #include "../mm_internal.h" | 36 | #include "../mm_internal.h" |
| 35 | 37 | ||
| @@ -1981,15 +1983,15 @@ int set_memory_global(unsigned long addr, int numpages) · 1945 unmodified lines | |||
| 1981 | __pgprot(_PAGE_GLOBAL), 0); | 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 | struct cpa_data cpa; | 1992 | struct cpa_data cpa; |
| 1987 | int ret; | 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 | /* Should not be working on unaligned addresses */ | 1995 | /* Should not be working on unaligned addresses */ |
| 1994 | if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr)) | 1996 | if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr)) |
| 1995 | addr &= PAGE_MASK; | 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 | return ret; | 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 | int set_memory_encrypted(unsigned long addr, int numpages) | 2040 | int set_memory_encrypted(unsigned long addr, int numpages) |
| 2028 | { | 2041 | { |
| 2029 | return __set_memory_enc_dec(addr, numpages, true); | 2042 | return __set_memory_enc_dec(addr, numpages, true); |
| @@ -8,6 +8,7 @@ config HYPERV · 7 unmodified lines | |||
| 8 | || (ARM64 && !CPU_BIG_ENDIAN)) | 8 | || (ARM64 && !CPU_BIG_ENDIAN)) |
| 9 | select PARAVIRT | 9 | select PARAVIRT |
| 10 | select X86_HV_CALLBACK_VECTOR if X86 | 10 | select X86_HV_CALLBACK_VECTOR if X86 |
| 11 | select VMAP_PFN | ||
| 11 | help | 12 | help |
| 12 | Select this option to run Linux as a Hyper-V client operating | 13 | Select this option to run Linux as a Hyper-V client operating |
| 13 | system. | 14 | system. |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/hyperv.h> | 17 | #include <linux/hyperv.h> |
| 18 | #include <linux/uio.h> | 18 | #include <linux/uio.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/set_memory.h> | ||
| 20 | #include <asm/page.h> | 21 | #include <asm/page.h> |
| 21 | #include <asm/mshyperv.h> | 22 | #include <asm/mshyperv.h> |
| 22 | 23 | ||
| @@ -456,7 +457,7 @@ nomem: · 433 unmodified lines | |||
| 456 | static int __vmbus_establish_gpadl(struct vmbus_channel *channel, | 457 | static int __vmbus_establish_gpadl(struct vmbus_channel *channel, |
| 457 | enum hv_gpadl_type type, void *kbuffer, | 458 | enum hv_gpadl_type type, void *kbuffer, |
| 458 | u32 size, u32 send_offset, | 459 | u32 size, u32 send_offset, |
| 459 | u32 *gpadl_handle) | 460 | struct vmbus_gpadl *gpadl) |
| 460 | { | 461 | { |
| 461 | struct vmbus_channel_gpadl_header *gpadlmsg; | 462 | struct vmbus_channel_gpadl_header *gpadlmsg; |
| 462 | struct vmbus_channel_gpadl_body *gpadl_body; | 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 | if (ret) | 475 | if (ret) |
| 475 | return ret; | 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 | init_completion(&msginfo->waitevent); | 487 | init_completion(&msginfo->waitevent); |
| 478 | msginfo->waiting_channel = channel; | 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 | /* At this point, we received the gpadl created msg */ | 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 | cleanup: | 555 | cleanup: |
| 543 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); | 556 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
| @@ -549,6 +562,11 @@ cleanup: · 5 unmodified lines | |||
| 549 | } | 562 | } |
| 550 | 563 | ||
| 551 | kfree(msginfo); | 564 | kfree(msginfo); |
| 565 | |||
| 566 | if (ret) | ||
| 567 | set_memory_encrypted((unsigned long)kbuffer, | ||
| 568 | PFN_UP(size)); | ||
| 569 | |||
| 552 | return ret; | 570 | return ret; |
| 553 | } | 571 | } |
| 554 | 572 | ||
| @@ -561,10 +579,10 @@ cleanup: · 6 unmodified lines | |||
| 561 | * @gpadl_handle: some funky thing | 579 | * @gpadl_handle: some funky thing |
| 562 | */ | 580 | */ |
| 563 | int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, | 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 | return __vmbus_establish_gpadl(channel, HV_GPADL_BUFFER, kbuffer, size, | 584 | return __vmbus_establish_gpadl(channel, HV_GPADL_BUFFER, kbuffer, size, |
| 567 | 0U, gpadl_handle); | 585 | 0U, gpadl); |
| 568 | } | 586 | } |
| 569 | EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); | 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 | if (!newchannel->max_pkt_size) | 683 | if (!newchannel->max_pkt_size) |
| 666 | newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE; | 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 | /* Establish the gpadl for the ring buffer */ | 686 | /* Establish the gpadl for the ring buffer */ |
| 678 | newchannel->ringbuffer_gpadlhandle = 0; | 687 | newchannel->ringbuffer_gpadlhandle.gpadl_handle = 0; |
| 679 | 688 | ||
| 680 | err = __vmbus_establish_gpadl(newchannel, HV_GPADL_RING, | 689 | err = __vmbus_establish_gpadl(newchannel, HV_GPADL_RING, |
| 681 | page_address(newchannel->ringbuffer_page), | 690 | page_address(newchannel->ringbuffer_page), |
| @@ -685,6 +694,16 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 3 unmodified lines | |||
| 685 | if (err) | 694 | if (err) |
| 686 | goto error_clean_ring; | 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 | /* Create and init the channel open message */ | 707 | /* Create and init the channel open message */ |
| 689 | open_info = kzalloc(sizeof(*open_info) + | 708 | open_info = kzalloc(sizeof(*open_info) + |
| 690 | sizeof(struct vmbus_channel_open_channel), | 709 | sizeof(struct vmbus_channel_open_channel), |
| @@ -701,7 +720,8 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 10 unmodified lines | |||
| 701 | open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL; | 720 | open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL; |
| 702 | open_msg->openid = newchannel->offermsg.child_relid; | 721 | open_msg->openid = newchannel->offermsg.child_relid; |
| 703 | open_msg->child_relid = newchannel->offermsg.child_relid; | 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 | * The unit of ->downstream_ringbuffer_pageoffset is HV_HYP_PAGE and | 726 | * The unit of ->downstream_ringbuffer_pageoffset is HV_HYP_PAGE and |
| 707 | * the unit of ->ringbuffer_send_offset (i.e. send_pages) is PAGE, so | 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 | error_free_info: | 779 | error_free_info: |
| 760 | kfree(open_info); | 780 | kfree(open_info); |
| 761 | error_free_gpadl: | 781 | error_free_gpadl: |
| 762 | vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); | 782 | vmbus_teardown_gpadl(newchannel, &newchannel->ringbuffer_gpadlhandle); |
| 763 | newchannel->ringbuffer_gpadlhandle = 0; | ||
| 764 | error_clean_ring: | 783 | error_clean_ring: |
| 765 | hv_ringbuffer_cleanup(&newchannel->outbound); | 784 | hv_ringbuffer_cleanup(&newchannel->outbound); |
| 766 | hv_ringbuffer_cleanup(&newchannel->inbound); | 785 | hv_ringbuffer_cleanup(&newchannel->inbound); |
| @@ -806,7 +825,7 @@ EXPORT_SYMBOL_GPL(vmbus_open); · 39 unmodified lines | |||
| 806 | /* | 825 | /* |
| 807 | * vmbus_teardown_gpadl -Teardown the specified GPADL handle | 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 | struct vmbus_channel_gpadl_teardown *msg; | 830 | struct vmbus_channel_gpadl_teardown *msg; |
| 812 | struct vmbus_channel_msginfo *info; | 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 | msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; | 845 | msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; |
| 827 | msg->child_relid = channel->offermsg.child_relid; | 846 | msg->child_relid = channel->offermsg.child_relid; |
| 828 | msg->gpadl = gpadl_handle; | 847 | msg->gpadl = gpadl->gpadl_handle; |
| 829 | 848 | ||
| 830 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); | 849 | spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
| 831 | list_add_tail(&info->msglistentry, | 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 | wait_for_completion(&info->waitevent); | 865 | wait_for_completion(&info->waitevent); |
| 847 | 866 | ||
| 867 | gpadl->gpadl_handle = 0; | ||
| 868 | |||
| 848 | post_msg_err: | 869 | post_msg_err: |
| 849 | /* | 870 | /* |
| 850 | * If the channel has been rescinded; | 871 | * If the channel has been rescinded; |
| @@ -859,6 +880,12 @@ post_msg_err: · 8 unmodified lines | |||
| 859 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 880 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
| 860 | 881 | ||
| 861 | kfree(info); | 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 | return ret; | 889 | return ret; |
| 863 | } | 890 | } |
| 864 | EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); | 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 | /* Tear down the gpadl for the channel's ring buffer */ | 962 | /* Tear down the gpadl for the channel's ring buffer */ |
| 936 | else if (channel->ringbuffer_gpadlhandle) { | 963 | else if (channel->ringbuffer_gpadlhandle.gpadl_handle) { |
| 937 | ret = vmbus_teardown_gpadl(channel, | 964 | ret = vmbus_teardown_gpadl(channel, &channel->ringbuffer_gpadlhandle); |
| 938 | channel->ringbuffer_gpadlhandle); | ||
| 939 | if (ret) { | 965 | if (ret) { |
| 940 | pr_err("Close failed: teardown gpadl return %d\n", ret); | 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 | * it is perhaps better to leak memory. | 969 | * it is perhaps better to leak memory. |
| 944 | */ | 970 | */ |
| 945 | } | 971 | } |
| 946 | |||
| 947 | channel->ringbuffer_gpadlhandle = 0; | ||
| 948 | } | 972 | } |
| 949 | 973 | ||
| 950 | if (!ret) | 974 | if (!ret) |
| @@ -1581,21 +1581,6 @@ cleanup: · 1580 unmodified lines | |||
| 1581 | return ret; | 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 | void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, | 1584 | void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, |
| 1600 | void (*sc_cr_cb)(struct vmbus_channel *new_sc)) | 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 | EXPORT_SYMBOL_GPL(vmbus_set_sc_create_callback); | 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 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, | 1591 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, |
| 1626 | void (*chn_rescind_cb)(struct vmbus_channel *)) | 1592 | void (*chn_rescind_cb)(struct vmbus_channel *)) |
| 1627 | { | 1593 | { |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | |||
| 19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 20 | #include <linux/hyperv.h> | 20 | #include <linux/hyperv.h> |
| 21 | #include <linux/export.h> | 21 | #include <linux/export.h> |
| 22 | #include <linux/io.h> | ||
| 23 | #include <linux/set_memory.h> | ||
| 22 | #include <asm/mshyperv.h> | 24 | #include <asm/mshyperv.h> |
| 23 | 25 | ||
| 24 | #include "hyperv_vmbus.h" | 26 | #include "hyperv_vmbus.h" |
| @@ -102,8 +104,9 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) · 77 unmodified lines | |||
| 102 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; | 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]); | 107 | msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0]; |
| 106 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); | 108 | msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1]; |
| 109 | |||
| 107 | msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU); | 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 | goto cleanup; | 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 | msginfo = kzalloc(sizeof(*msginfo) + | 281 | msginfo = kzalloc(sizeof(*msginfo) + |
| 220 | sizeof(struct vmbus_channel_initiate_contact), | 282 | sizeof(struct vmbus_channel_initiate_contact), |
| 221 | GFP_KERNEL); | 283 | GFP_KERNEL); |
| @@ -303,10 +365,31 @@ void vmbus_disconnect(void) · 81 unmodified lines | |||
| 303 | vmbus_connection.int_page = NULL; | 365 | vmbus_connection.int_page = NULL; |
| 304 | } | 366 | } |
| 305 | 367 | ||
| 306 | hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); | 368 | if (hv_is_isolation_supported()) { |
| 307 | hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); | 369 | /* |
| 308 | vmbus_connection.monitor_pages[0] = NULL; | 370 | * memunmap() checks input address is ioremap address or not |
| 309 | vmbus_connection.monitor_pages[1] = NULL; | 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 | ++channel->sig_events; | 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 | EXPORT_SYMBOL_GPL(vmbus_set_event); | 539 | EXPORT_SYMBOL_GPL(vmbus_set_event); |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | */ | 8 | */ |
| 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/io.h> | ||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
| 13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| @@ -97,7 +98,13 @@ int hv_post_message(union hv_connection_id connection_id, · 83 unmodified lines | |||
| 97 | aligned_msg->payload_size = payload_size; | 98 | aligned_msg->payload_size = payload_size; |
| 98 | memcpy((void *)aligned_msg->payload, payload, payload_size); | 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 | /* Preemption must remain disabled until after the hypercall | 109 | /* Preemption must remain disabled until after the hypercall |
| 103 | * so some other thread can't get scheduled onto this cpu and | 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 | tasklet_init(&hv_cpu->msg_dpc, | 143 | tasklet_init(&hv_cpu->msg_dpc, |
| 137 | vmbus_on_msg_dpc, (unsigned long) hv_cpu); | 144 | vmbus_on_msg_dpc, (unsigned long) hv_cpu); |
| 138 | 145 | ||
| 139 | hv_cpu->synic_message_page = | 146 | /* |
| 140 | (void *)get_zeroed_page(GFP_ATOMIC); | 147 | * Synic message and event pages are allocated by paravisor. |
| 141 | if (hv_cpu->synic_message_page == NULL) { | 148 | * Skip these pages allocation here. |
| 142 | pr_err("Unable to allocate SYNIC message page\n"); | 149 | */ |
| 143 | goto err; | 150 | if (!hv_isolation_type_snp()) { |
| 144 | } | 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); | 158 | hv_cpu->synic_event_page = |
| 147 | if (hv_cpu->synic_event_page == NULL) { | 159 | (void *)get_zeroed_page(GFP_ATOMIC); |
| 148 | pr_err("Unable to allocate SYNIC event page\n"); | 160 | if (hv_cpu->synic_event_page == NULL) { |
| 149 | goto err; | 161 | pr_err("Unable to allocate SYNIC event page\n"); |
| 162 | goto err; | ||
| 163 | } | ||
| 150 | } | 164 | } |
| 151 | 165 | ||
| 152 | hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); | 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 | /* Setup the Synic's message page */ | 215 | /* Setup the Synic's message page */ |
| 202 | simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); | 216 | simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); |
| 203 | simp.simp_enabled = 1; | 217 | simp.simp_enabled = 1; |
| 204 | simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) | 218 | |
| 205 | >> HV_HYP_PAGE_SHIFT; | 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 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); | 230 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); |
| 208 | 231 | ||
| 209 | /* Setup the Synic's event page */ | 232 | /* Setup the Synic's event page */ |
| 210 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); | 233 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); |
| 211 | siefp.siefp_enabled = 1; | 234 | siefp.siefp_enabled = 1; |
| 212 | siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) | 235 | |
| 213 | >> HV_HYP_PAGE_SHIFT; | 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 | hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); | 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 | void hv_synic_disable_regs(unsigned int cpu) | 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 | union hv_synic_sint shared_sint; | 295 | union hv_synic_sint shared_sint; |
| 261 | union hv_synic_simp simp; | 296 | union hv_synic_simp simp; |
| 262 | union hv_synic_siefp siefp; | 297 | union hv_synic_siefp siefp; |
| @@ -273,14 +308,27 @@ void hv_synic_disable_regs(unsigned int cpu) · 10 unmodified lines | |||
| 273 | shared_sint.as_uint64); | 308 | shared_sint.as_uint64); |
| 274 | 309 | ||
| 275 | simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); | 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 | simp.simp_enabled = 0; | 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 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); | 323 | hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); |
| 280 | 324 | ||
| 281 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); | 325 | siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); |
| 282 | siefp.siefp_enabled = 0; | 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 | hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); | 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 | EXPORT_SYMBOL_GPL(hv_is_isolation_supported); | 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 | void __weak hv_setup_vmbus_handler(void (*handler)(void)) | 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 | EXPORT_SYMBOL_GPL(hyperv_cleanup); | 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 | * is child->parent notification | 241 | * is child->parent notification |
| 242 | */ | 242 | */ |
| 243 | struct hv_monitor_page *monitor_pages[2]; | 243 | struct hv_monitor_page *monitor_pages[2]; |
| 244 | void *monitor_pages_original[2]; | ||
| 245 | phys_addr_t monitor_pages_pa[2]; | ||
| 244 | struct list_head chn_msg_list; | 246 | struct list_head chn_msg_list; |
| 245 | spinlock_t channelmsg_lock; | 247 | spinlock_t channelmsg_lock; |
| 246 | 248 | ||
| @@ -17,6 +17,8 @@ · 16 unmodified lines | |||
| 17 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/prefetch.h> | 19 | #include <linux/prefetch.h> |
| 20 | #include <linux/io.h> | ||
| 21 | #include <asm/mshyperv.h> | ||
| 20 | 22 | ||
| 21 | #include "hyperv_vmbus.h" | 23 | #include "hyperv_vmbus.h" |
| 22 | 24 | ||
| @@ -183,8 +185,10 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel) · 160 unmodified lines | |||
| 183 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | 185 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
| 184 | struct page *pages, u32 page_cnt, u32 max_pkt_size) | 186 | struct page *pages, u32 page_cnt, u32 max_pkt_size) |
| 185 | { | 187 | { |
| 186 | int i; | ||
| 187 | struct page **pages_wraparound; | 188 | struct page **pages_wraparound; |
| 189 | unsigned long *pfns_wraparound; | ||
| 190 | u64 pfn; | ||
| 191 | int i; | ||
| 188 | 192 | ||
| 189 | BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); | 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 | * First page holds struct hv_ring_buffer, do wraparound mapping for | 196 | * First page holds struct hv_ring_buffer, do wraparound mapping for |
| 193 | * the rest. | 197 | * the rest. |
| 194 | */ | 198 | */ |
| 195 | pages_wraparound = kcalloc(page_cnt * 2 - 1, sizeof(struct page *), | 199 | if (hv_isolation_type_snp()) { |
| 196 | GFP_KERNEL); | 200 | pfn = page_to_pfn(pages) + |
| 197 | if (!pages_wraparound) | 201 | PFN_DOWN(ms_hyperv.shared_gpa_boundary); |
| 198 | return -ENOMEM; | 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; | 208 | pfns_wraparound[0] = pfn; |
| 201 | for (i = 0; i < 2 * (page_cnt - 1); i++) | 209 | for (i = 0; i < 2 * (page_cnt - 1); i++) |
| 202 | pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1]; | 210 | pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1; |
| 203 | 211 | ||
| 204 | ring_info->ring_buffer = (struct hv_ring_buffer *) | 212 | ring_info->ring_buffer = (struct hv_ring_buffer *) |
| 205 | vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL); | 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 | ring_info->ring_buffer->read_index = | 244 | ring_info->ring_buffer->read_index = |
| 214 | ring_info->ring_buffer->write_index = 0; | 245 | ring_info->ring_buffer->write_index = 0; |
| @@ -1075,14 +1075,15 @@ struct netvsc_device { · 1074 unmodified lines | |||
| 1075 | /* Receive buffer allocated by us but manages by NetVSP */ | 1075 | /* Receive buffer allocated by us but manages by NetVSP */ |
| 1076 | void *recv_buf; | 1076 | void *recv_buf; |
| 1077 | u32 recv_buf_size; /* allocated bytes */ | 1077 | u32 recv_buf_size; /* allocated bytes */ |
| 1078 | u32 recv_buf_gpadl_handle; | 1078 | struct vmbus_gpadl recv_buf_gpadl_handle; |
| 1079 | u32 recv_section_cnt; | 1079 | u32 recv_section_cnt; |
| 1080 | u32 recv_section_size; | 1080 | u32 recv_section_size; |
| 1081 | u32 recv_completion_cnt; | 1081 | u32 recv_completion_cnt; |
| 1082 | 1082 | ||
| 1083 | /* Send buffer allocated by us */ | 1083 | /* Send buffer allocated by us */ |
| 1084 | void *send_buf; | 1084 | void *send_buf; |
| 1085 | u32 send_buf_gpadl_handle; | 1085 | u32 send_buf_size; |
| 1086 | struct vmbus_gpadl send_buf_gpadl_handle; | ||
| 1086 | u32 send_section_cnt; | 1087 | u32 send_section_cnt; |
| 1087 | u32 send_section_size; | 1088 | u32 send_section_size; |
| 1088 | unsigned long *send_section_map; | 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 | int ret; | 279 | int ret; |
| 280 | 280 | ||
| 281 | if (net_device->recv_buf_gpadl_handle) { | 281 | if (net_device->recv_buf_gpadl_handle.gpadl_handle) { |
| 282 | ret = vmbus_teardown_gpadl(device->channel, | 282 | ret = vmbus_teardown_gpadl(device->channel, |
| 283 | net_device->recv_buf_gpadl_handle); | 283 | &net_device->recv_buf_gpadl_handle); |
| 284 | 284 | ||
| 285 | /* If we failed here, we might as well return and have a leak | 285 | /* If we failed here, we might as well return and have a leak |
| 286 | * rather than continue and a bugchk | 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 | "unable to teardown receive buffer's gpadl\n"); | 290 | "unable to teardown receive buffer's gpadl\n"); |
| 291 | return; | 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 | int ret; | 300 | int ret; |
| 302 | 301 | ||
| 303 | if (net_device->send_buf_gpadl_handle) { | 302 | if (net_device->send_buf_gpadl_handle.gpadl_handle) { |
| 304 | ret = vmbus_teardown_gpadl(device->channel, | 303 | ret = vmbus_teardown_gpadl(device->channel, |
| 305 | net_device->send_buf_gpadl_handle); | 304 | &net_device->send_buf_gpadl_handle); |
| 306 | 305 | ||
| 307 | /* If we failed here, we might as well return and have a leak | 306 | /* If we failed here, we might as well return and have a leak |
| 308 | * rather than continue and a bugchk | 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 | "unable to teardown send buffer's gpadl\n"); | 311 | "unable to teardown send buffer's gpadl\n"); |
| 313 | return; | 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 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 378 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| 381 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; | 379 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; |
| 382 | init_packet->msg.v1_msg.send_recv_buf. | 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 | init_packet->msg.v1_msg. | 382 | init_packet->msg.v1_msg. |
| 385 | send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; | 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 | ret = -ENOMEM; | 461 | ret = -ENOMEM; |
| 464 | goto cleanup; | 462 | goto cleanup; |
| 465 | } | 463 | } |
| 464 | net_device->send_buf_size = buf_size; | ||
| 466 | 465 | ||
| 467 | /* Establish the gpadl handle for this buffer on this | 466 | /* Establish the gpadl handle for this buffer on this |
| 468 | * channel. Note: This call uses the vmbus connection rather | 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 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 481 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| 483 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; | 482 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; |
| 484 | init_packet->msg.v1_msg.send_send_buf.gpadl_handle = | 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 | init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; | 485 | init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; |
| 487 | 486 | ||
| 488 | trace_nvsp_send(ndev, init_packet); | 487 | trace_nvsp_send(ndev, init_packet); |
| @@ -58,11 +58,11 @@ struct hv_uio_private_data { · 57 unmodified lines | |||
| 58 | atomic_t refcnt; | 58 | atomic_t refcnt; |
| 59 | 59 | ||
| 60 | void *recv_buf; | 60 | void *recv_buf; |
| 61 | u32 recv_gpadl; | 61 | struct vmbus_gpadl recv_gpadl; |
| 62 | char recv_name[32]; /* "recv_4294967295" */ | 62 | char recv_name[32]; /* "recv_4294967295" */ |
| 63 | 63 | ||
| 64 | void *send_buf; | 64 | void *send_buf; |
| 65 | u32 send_gpadl; | 65 | struct vmbus_gpadl send_gpadl; |
| 66 | char send_name[32]; | 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 | static void | 179 | static void |
| 180 | hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) | 180 | hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) |
| 181 | { | 181 | { |
| 182 | if (pdata->send_gpadl) { | 182 | if (pdata->send_gpadl.gpadl_handle) { |
| 183 | vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl); | 183 | vmbus_teardown_gpadl(dev->channel, &pdata->send_gpadl); |
| 184 | pdata->send_gpadl = 0; | ||
| 185 | vfree(pdata->send_buf); | 184 | vfree(pdata->send_buf); |
| 186 | } | 185 | } |
| 187 | 186 | ||
| 188 | if (pdata->recv_gpadl) { | 187 | if (pdata->recv_gpadl.gpadl_handle) { |
| 189 | vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl); | 188 | vmbus_teardown_gpadl(dev->channel, &pdata->recv_gpadl); |
| 190 | pdata->recv_gpadl = 0; | ||
| 191 | vfree(pdata->recv_buf); | 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 | /* put Global Physical Address Label in name */ | 302 | /* put Global Physical Address Label in name */ |
| 305 | snprintf(pdata->recv_name, sizeof(pdata->recv_name), | 303 | snprintf(pdata->recv_name, sizeof(pdata->recv_name), |
| 306 | "recv:%u", pdata->recv_gpadl); | 304 | "recv:%u", pdata->recv_gpadl.gpadl_handle); |
| 307 | pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; | 305 | pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; |
| 308 | pdata->info.mem[RECV_BUF_MAP].addr | 306 | pdata->info.mem[RECV_BUF_MAP].addr |
| 309 | = (uintptr_t)pdata->recv_buf; | 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 | snprintf(pdata->send_name, sizeof(pdata->send_name), | 324 | snprintf(pdata->send_name, sizeof(pdata->send_name), |
| 327 | "send:%u", pdata->send_gpadl); | 325 | "send:%u", pdata->send_gpadl.gpadl_handle); |
| 328 | pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; | 326 | pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; |
| 329 | pdata->info.mem[SEND_BUF_MAP].addr | 327 | pdata->info.mem[SEND_BUF_MAP].addr |
| 330 | = (uintptr_t)pdata->send_buf; | 328 | = (uintptr_t)pdata->send_buf; |
| @@ -158,6 +158,7 @@ struct ms_hyperv_tsc_page { · 157 unmodified lines | |||
| 158 | #define HVCALL_RETARGET_INTERRUPT 0x007e | 158 | #define HVCALL_RETARGET_INTERRUPT 0x007e |
| 159 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af | 159 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af |
| 160 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 | 160 | #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 |
| 161 | #define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db | ||
| 161 | 162 | ||
| 162 | /* Extended hypercalls */ | 163 | /* Extended hypercalls */ |
| 163 | #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 | 164 | #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 |
| @@ -35,7 +35,17 @@ struct ms_hyperv_info { · 34 unmodified lines | |||
| 35 | u32 max_vp_index; | 35 | u32 max_vp_index; |
| 36 | u32 max_lp_index; | 36 | u32 max_lp_index; |
| 37 | u32 isolation_config_a; | 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 | extern struct ms_hyperv_info ms_hyperv; | 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 | extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); | 55 | extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); |
| 46 | extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); | 56 | extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); |
| 57 | extern bool hv_isolation_type_snp(void); | ||
| 47 | 58 | ||
| 48 | /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ | 59 | /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ |
| 49 | static inline int hv_result(u64 status) | 60 | static inline int hv_result(u64 status) |
| @@ -254,12 +265,19 @@ bool hv_is_hyperv_initialized(void); · 204 unmodified lines | |||
| 254 | bool hv_is_hibernation_supported(void); | 265 | bool hv_is_hibernation_supported(void); |
| 255 | enum hv_isolation_type hv_get_isolation_type(void); | 266 | enum hv_isolation_type hv_get_isolation_type(void); |
| 256 | bool hv_is_isolation_supported(void); | 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 | void hyperv_cleanup(void); | 270 | void hyperv_cleanup(void); |
| 258 | bool hv_query_ext_cap(u64 cap_query); | 271 | bool hv_query_ext_cap(u64 cap_query); |
| 259 | #else /* CONFIG_HYPERV */ | 272 | #else /* CONFIG_HYPERV */ |
| 260 | static inline bool hv_is_hyperv_initialized(void) { return false; } | 273 | static inline bool hv_is_hyperv_initialized(void) { return false; } |
| 261 | static inline bool hv_is_hibernation_supported(void) { return false; } | 274 | static inline bool hv_is_hibernation_supported(void) { return false; } |
| 262 | static inline void hyperv_cleanup(void) {} | 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 | #endif /* CONFIG_HYPERV */ | 281 | #endif /* CONFIG_HYPERV */ |
| 264 | 282 | ||
| 265 | #endif | 283 | #endif |
| @@ -803,6 +803,12 @@ struct vmbus_device { · 802 unmodified lines | |||
| 803 | 803 | ||
| 804 | #define VMBUS_DEFAULT_MAX_PKT_SIZE 4096 | 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 | struct vmbus_channel { | 812 | struct vmbus_channel { |
| 807 | struct list_head listentry; | 813 | struct list_head listentry; |
| 808 | 814 | ||
| @@ -822,7 +828,7 @@ struct vmbus_channel { · 13 unmodified lines | |||
| 822 | bool rescind_ref; /* got rescind msg, got channel reference */ | 828 | bool rescind_ref; /* got rescind msg, got channel reference */ |
| 823 | struct completion rescind_event; | 829 | struct completion rescind_event; |
| 824 | 830 | ||
| 825 | u32 ringbuffer_gpadlhandle; | 831 | struct vmbus_gpadl ringbuffer_gpadlhandle; |
| 826 | 832 | ||
| 827 | /* Allocated memory for ring buffer */ | 833 | /* Allocated memory for ring buffer */ |
| 828 | struct page *ringbuffer_page; | 834 | struct page *ringbuffer_page; |
| @@ -1100,19 +1106,6 @@ void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, · 271 unmodified lines | |||
| 1100 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, | 1106 | void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, |
| 1101 | void (*chn_rescind_cb)(struct vmbus_channel *)); | 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 | /* The format must be the same as struct vmdata_gpa_direct */ | 1109 | /* The format must be the same as struct vmdata_gpa_direct */ |
| 1117 | struct vmbus_channel_packet_page_buffer { | 1110 | struct vmbus_channel_packet_page_buffer { |
| 1118 | u16 type; | 1111 | u16 type; |
| @@ -1192,10 +1185,10 @@ extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, · 73 unmodified lines | |||
| 1192 | extern int vmbus_establish_gpadl(struct vmbus_channel *channel, | 1185 | extern int vmbus_establish_gpadl(struct vmbus_channel *channel, |
| 1193 | void *kbuffer, | 1186 | void *kbuffer, |
| 1194 | u32 size, | 1187 | u32 size, |
| 1195 | u32 *gpadl_handle); | 1188 | struct vmbus_gpadl *gpadl); |
| 1196 | 1189 | ||
| 1197 | extern int vmbus_teardown_gpadl(struct vmbus_channel *channel, | 1190 | extern int vmbus_teardown_gpadl(struct vmbus_channel *channel, |
| 1198 | u32 gpadl_handle); | 1191 | struct vmbus_gpadl *gpadl); |
| 1199 | 1192 | ||
| 1200 | void vmbus_reset_channel_cb(struct vmbus_channel *channel); | 1193 | void vmbus_reset_channel_cb(struct vmbus_channel *channel); |
| 1201 | 1194 | ||