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

Merge tag 'hyperv-next-signed-20211102' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

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

+761 -172
+1 -1
arch/x86/hyperv/Makefile
··· 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
+61 -21
arch/x86/hyperv/hv_init.c
··· 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); 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 + } 44 74 45 75 static int hv_cpu_init(unsigned int cpu) 46 76 { ··· 115 85 } 116 86 } 117 87 118 - return 0; 88 + return hyperv_init_ghcb(); 119 89 } 120 90 121 91 static void (*hv_reenlightenment_cb)(void); ··· 169 139 struct hv_reenlightenment_control re_ctrl = { 170 140 .vector = HYPERV_REENLIGHTENMENT_VECTOR, 171 141 .enabled = 1, 172 - .target_vp = hv_vp_index[smp_processor_id()] 173 142 }; 174 143 struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; 175 144 ··· 182 153 /* Make sure callback is registered before we write to MSRs */ 183 154 wmb(); 184 155 156 + re_ctrl.target_vp = hv_vp_index[get_cpu()]; 157 + 185 158 wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl)); 186 159 wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); 160 + 161 + put_cpu(); 187 162 } 188 163 EXPORT_SYMBOL_GPL(set_hv_tscchange_cb); 189 164 ··· 210 177 { 211 178 struct hv_reenlightenment_control re_ctrl; 212 179 unsigned int new_cpu; 180 + void **ghcb_va; 181 + 182 + if (hv_ghcb_pg) { 183 + ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg); 184 + if (*ghcb_va) 185 + memunmap(*ghcb_va); 186 + *ghcb_va = NULL; 187 + } 213 188 214 189 hv_common_cpu_die(cpu); 215 190 ··· 407 366 goto common_free; 408 367 } 409 368 369 + if (hv_isolation_type_snp()) { 370 + hv_ghcb_pg = alloc_percpu(union hv_ghcb *); 371 + if (!hv_ghcb_pg) 372 + goto free_vp_assist_page; 373 + } 374 + 410 375 cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online", 411 376 hv_cpu_init, hv_cpu_die); 412 377 if (cpuhp < 0) 413 - goto free_vp_assist_page; 378 + goto free_ghcb_page; 414 379 415 380 /* 416 381 * Setup the hypercall page and enable hypercalls. ··· 426 379 guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); 427 380 wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); 428 381 382 + /* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ 383 + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id); 384 + 429 385 hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, 430 386 VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, 431 387 VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, 432 388 __builtin_return_address(0)); 433 - if (hv_hypercall_pg == NULL) { 434 - wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); 435 - goto remove_cpuhp_state; 436 - } 389 + if (hv_hypercall_pg == NULL) 390 + goto clean_guest_os_id; 437 391 438 392 rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); 439 393 hypercall_msr.enable = 1; ··· 504 456 hv_query_ext_cap(0); 505 457 return; 506 458 507 - remove_cpuhp_state: 459 + clean_guest_os_id: 460 + wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); 461 + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); 508 462 cpuhp_remove_state(cpuhp); 463 + free_ghcb_page: 464 + free_percpu(hv_ghcb_pg); 509 465 free_vp_assist_page: 510 466 kfree(hv_vp_assist_page); 511 467 hv_vp_assist_page = NULL; ··· 528 476 529 477 /* Reset our OS id */ 530 478 wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); 479 + hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); 531 480 532 481 /* 533 482 * Reset hypercall page reference before reset the page, ··· 599 546 return hypercall_msr.enable; 600 547 } 601 548 EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized); 602 - 603 - enum hv_isolation_type hv_get_isolation_type(void) 604 - { 605 - if (!(ms_hyperv.priv_high & HV_ISOLATION)) 606 - return HV_ISOLATION_TYPE_NONE; 607 - return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); 608 - } 609 - EXPORT_SYMBOL_GPL(hv_get_isolation_type); 610 - 611 - bool hv_is_isolation_supported(void) 612 - { 613 - return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; 614 - }
+289
arch/x86/hyperv/ivm.c
··· 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 + }
+17
arch/x86/include/asm/hyperv-tlfs.h
··· 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 */
+57 -13
arch/x86/include/asm/mshyperv.h
··· 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 - 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 21 31 22 #define hv_get_raw_timer() rdtsc_ordered() 32 23 ··· 29 38 extern void *hv_hypercall_pg; 30 39 31 40 extern u64 hv_current_partition_id; 41 + 42 + extern union hv_ghcb __percpu **hv_ghcb_pg; 32 43 33 44 int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); 34 45 int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); ··· 181 188 int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, 182 189 struct hv_interrupt_entry *entry); 183 190 int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); 191 + int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible); 192 + 193 + #ifdef CONFIG_AMD_MEM_ENCRYPT 194 + void hv_ghcb_msr_write(u64 msr, u64 value); 195 + void hv_ghcb_msr_read(u64 msr, u64 *value); 196 + #else 197 + static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} 198 + static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {} 199 + #endif 200 + 201 + extern bool hv_isolation_type_snp(void); 202 + 203 + static inline bool hv_is_synic_reg(unsigned int reg) 204 + { 205 + if ((reg >= HV_REGISTER_SCONTROL) && 206 + (reg <= HV_REGISTER_SINT15)) 207 + return true; 208 + return false; 209 + } 210 + 211 + static inline u64 hv_get_register(unsigned int reg) 212 + { 213 + u64 value; 214 + 215 + if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) 216 + hv_ghcb_msr_read(reg, &value); 217 + else 218 + rdmsrl(reg, value); 219 + return value; 220 + } 221 + 222 + static inline void hv_set_register(unsigned int reg, u64 value) 223 + { 224 + if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) { 225 + hv_ghcb_msr_write(reg, value); 226 + 227 + /* Write proxy bit via wrmsl instruction */ 228 + if (reg >= HV_REGISTER_SINT0 && 229 + reg <= HV_REGISTER_SINT15) 230 + wrmsrl(reg, value | 1 << 20); 231 + } else { 232 + wrmsrl(reg, value); 233 + } 234 + } 184 235 185 236 #else /* CONFIG_HYPERV */ 186 237 static inline void hyperv_init(void) {} ··· 239 202 static inline int hyperv_flush_guest_mapping(u64 as) { return -1; } 240 203 static inline int hyperv_flush_guest_mapping_range(u64 as, 241 204 hyperv_fill_flush_list_func fill_func, void *data) 205 + { 206 + return -1; 207 + } 208 + static inline void hv_set_register(unsigned int reg, u64 value) { } 209 + static inline u64 hv_get_register(unsigned int reg) { return 0; } 210 + static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages, 211 + bool visible) 242 212 { 243 213 return -1; 244 214 }
+5
arch/x86/kernel/cpu/mshyperv.c
··· 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) {
+18 -5
arch/x86/mm/pat/set_memory.c
··· 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 ··· 1983 1981 __pgprot(_PAGE_GLOBAL), 0); 1984 1982 } 1985 1983 1986 - static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) 1984 + /* 1985 + * __set_memory_enc_pgtable() is used for the hypervisors that get 1986 + * informed about "encryption" status via page tables. 1987 + */ 1988 + static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc) 1987 1989 { 1988 1990 struct cpa_data cpa; 1989 1991 int ret; 1990 - 1991 - /* Nothing to do if memory encryption is not active */ 1992 - if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT)) 1993 - return 0; 1994 1992 1995 1993 /* Should not be working on unaligned addresses */ 1996 1994 if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr)) ··· 2024 2022 cpa_flush(&cpa, 0); 2025 2023 2026 2024 return ret; 2025 + } 2026 + 2027 + static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) 2028 + { 2029 + if (hv_is_isolation_supported()) 2030 + return hv_set_mem_host_visibility(addr, numpages, !enc); 2031 + 2032 + if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) 2033 + return __set_memory_enc_pgtable(addr, numpages, enc); 2034 + 2035 + return 0; 2027 2036 } 2028 2037 2029 2038 int set_memory_encrypted(unsigned long addr, int numpages)
+1
drivers/hv/Kconfig
··· 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.
+48 -24
drivers/hv/channel.c
··· 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 ··· 457 456 static int __vmbus_establish_gpadl(struct vmbus_channel *channel, 458 457 enum hv_gpadl_type type, void *kbuffer, 459 458 u32 size, u32 send_offset, 460 - u32 *gpadl_handle) 459 + struct vmbus_gpadl *gpadl) 461 460 { 462 461 struct vmbus_channel_gpadl_header *gpadlmsg; 463 462 struct vmbus_channel_gpadl_body *gpadl_body; ··· 474 473 ret = create_gpadl_header(type, kbuffer, size, send_offset, &msginfo); 475 474 if (ret) 476 475 return ret; 476 + 477 + ret = set_memory_decrypted((unsigned long)kbuffer, 478 + PFN_UP(size)); 479 + if (ret) { 480 + dev_warn(&channel->device_obj->device, 481 + "Failed to set host visibility for new GPADL %d.\n", 482 + ret); 483 + return ret; 484 + } 477 485 478 486 init_completion(&msginfo->waitevent); 479 487 msginfo->waiting_channel = channel; ··· 547 537 } 548 538 549 539 /* At this point, we received the gpadl created msg */ 550 - *gpadl_handle = gpadlmsg->gpadl; 540 + gpadl->gpadl_handle = gpadlmsg->gpadl; 541 + gpadl->buffer = kbuffer; 542 + gpadl->size = size; 543 + 551 544 552 545 cleanup: 553 546 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); ··· 562 549 } 563 550 564 551 kfree(msginfo); 552 + 553 + if (ret) 554 + set_memory_encrypted((unsigned long)kbuffer, 555 + PFN_UP(size)); 556 + 565 557 return ret; 566 558 } 567 559 ··· 579 561 * @gpadl_handle: some funky thing 580 562 */ 581 563 int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, 582 - u32 size, u32 *gpadl_handle) 564 + u32 size, struct vmbus_gpadl *gpadl) 583 565 { 584 566 return __vmbus_establish_gpadl(channel, HV_GPADL_BUFFER, kbuffer, size, 585 - 0U, gpadl_handle); 567 + 0U, gpadl); 586 568 } 587 569 EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); 588 570 ··· 683 665 if (!newchannel->max_pkt_size) 684 666 newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE; 685 667 686 - err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages, 0); 687 - if (err) 688 - goto error_clean_ring; 689 - 690 - err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages], 691 - recv_pages, newchannel->max_pkt_size); 692 - if (err) 693 - goto error_clean_ring; 694 - 695 668 /* Establish the gpadl for the ring buffer */ 696 - newchannel->ringbuffer_gpadlhandle = 0; 669 + newchannel->ringbuffer_gpadlhandle.gpadl_handle = 0; 697 670 698 671 err = __vmbus_establish_gpadl(newchannel, HV_GPADL_RING, 699 672 page_address(newchannel->ringbuffer_page), ··· 693 684 &newchannel->ringbuffer_gpadlhandle); 694 685 if (err) 695 686 goto error_clean_ring; 687 + 688 + err = hv_ringbuffer_init(&newchannel->outbound, 689 + page, send_pages, 0); 690 + if (err) 691 + goto error_free_gpadl; 692 + 693 + err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages], 694 + recv_pages, newchannel->max_pkt_size); 695 + if (err) 696 + goto error_free_gpadl; 696 697 697 698 /* Create and init the channel open message */ 698 699 open_info = kzalloc(sizeof(*open_info) + ··· 720 701 open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL; 721 702 open_msg->openid = newchannel->offermsg.child_relid; 722 703 open_msg->child_relid = newchannel->offermsg.child_relid; 723 - open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; 704 + open_msg->ringbuffer_gpadlhandle 705 + = newchannel->ringbuffer_gpadlhandle.gpadl_handle; 724 706 /* 725 707 * The unit of ->downstream_ringbuffer_pageoffset is HV_HYP_PAGE and 726 708 * the unit of ->ringbuffer_send_offset (i.e. send_pages) is PAGE, so ··· 779 759 error_free_info: 780 760 kfree(open_info); 781 761 error_free_gpadl: 782 - vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); 783 - newchannel->ringbuffer_gpadlhandle = 0; 762 + vmbus_teardown_gpadl(newchannel, &newchannel->ringbuffer_gpadlhandle); 784 763 error_clean_ring: 785 764 hv_ringbuffer_cleanup(&newchannel->outbound); 786 765 hv_ringbuffer_cleanup(&newchannel->inbound); ··· 825 806 /* 826 807 * vmbus_teardown_gpadl -Teardown the specified GPADL handle 827 808 */ 828 - int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) 809 + int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpadl) 829 810 { 830 811 struct vmbus_channel_gpadl_teardown *msg; 831 812 struct vmbus_channel_msginfo *info; ··· 844 825 845 826 msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; 846 827 msg->child_relid = channel->offermsg.child_relid; 847 - msg->gpadl = gpadl_handle; 828 + msg->gpadl = gpadl->gpadl_handle; 848 829 849 830 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 850 831 list_add_tail(&info->msglistentry, ··· 864 845 865 846 wait_for_completion(&info->waitevent); 866 847 848 + gpadl->gpadl_handle = 0; 849 + 867 850 post_msg_err: 868 851 /* 869 852 * If the channel has been rescinded; ··· 880 859 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 881 860 882 861 kfree(info); 862 + 863 + ret = set_memory_encrypted((unsigned long)gpadl->buffer, 864 + PFN_UP(gpadl->size)); 865 + if (ret) 866 + pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret); 867 + 883 868 return ret; 884 869 } 885 870 EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); ··· 960 933 } 961 934 962 935 /* Tear down the gpadl for the channel's ring buffer */ 963 - else if (channel->ringbuffer_gpadlhandle) { 964 - ret = vmbus_teardown_gpadl(channel, 965 - channel->ringbuffer_gpadlhandle); 936 + else if (channel->ringbuffer_gpadlhandle.gpadl_handle) { 937 + ret = vmbus_teardown_gpadl(channel, &channel->ringbuffer_gpadlhandle); 966 938 if (ret) { 967 939 pr_err("Close failed: teardown gpadl return %d\n", ret); 968 940 /* ··· 969 943 * it is perhaps better to leak memory. 970 944 */ 971 945 } 972 - 973 - channel->ringbuffer_gpadlhandle = 0; 974 946 } 975 947 976 948 if (!ret)
-34
drivers/hv/channel_mgmt.c
··· 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 { 1602 1587 primary_channel->sc_creation_callback = sc_cr_cb; 1603 1588 } 1604 1589 EXPORT_SYMBOL_GPL(vmbus_set_sc_create_callback); 1605 - 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 1590 1625 1591 void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, 1626 1592 void (*chn_rescind_cb)(struct vmbus_channel *))
+94 -7
drivers/hv/connection.c
··· 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" ··· 104 102 vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; 105 103 } 106 104 107 - msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); 108 - msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); 105 + msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0]; 106 + msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1]; 107 + 109 108 msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU); 110 109 111 110 /* ··· 219 216 goto cleanup; 220 217 } 221 218 219 + vmbus_connection.monitor_pages_original[0] 220 + = vmbus_connection.monitor_pages[0]; 221 + vmbus_connection.monitor_pages_original[1] 222 + = vmbus_connection.monitor_pages[1]; 223 + vmbus_connection.monitor_pages_pa[0] 224 + = virt_to_phys(vmbus_connection.monitor_pages[0]); 225 + vmbus_connection.monitor_pages_pa[1] 226 + = virt_to_phys(vmbus_connection.monitor_pages[1]); 227 + 228 + if (hv_is_isolation_supported()) { 229 + ret = set_memory_decrypted((unsigned long) 230 + vmbus_connection.monitor_pages[0], 231 + 1); 232 + ret |= set_memory_decrypted((unsigned long) 233 + vmbus_connection.monitor_pages[1], 234 + 1); 235 + if (ret) 236 + goto cleanup; 237 + 238 + /* 239 + * Isolation VM with AMD SNP needs to access monitor page via 240 + * address space above shared gpa boundary. 241 + */ 242 + if (hv_isolation_type_snp()) { 243 + vmbus_connection.monitor_pages_pa[0] += 244 + ms_hyperv.shared_gpa_boundary; 245 + vmbus_connection.monitor_pages_pa[1] += 246 + ms_hyperv.shared_gpa_boundary; 247 + 248 + vmbus_connection.monitor_pages[0] 249 + = memremap(vmbus_connection.monitor_pages_pa[0], 250 + HV_HYP_PAGE_SIZE, 251 + MEMREMAP_WB); 252 + if (!vmbus_connection.monitor_pages[0]) { 253 + ret = -ENOMEM; 254 + goto cleanup; 255 + } 256 + 257 + vmbus_connection.monitor_pages[1] 258 + = memremap(vmbus_connection.monitor_pages_pa[1], 259 + HV_HYP_PAGE_SIZE, 260 + MEMREMAP_WB); 261 + if (!vmbus_connection.monitor_pages[1]) { 262 + ret = -ENOMEM; 263 + goto cleanup; 264 + } 265 + } 266 + 267 + /* 268 + * Set memory host visibility hvcall smears memory 269 + * and so zero monitor pages here. 270 + */ 271 + memset(vmbus_connection.monitor_pages[0], 0x00, 272 + HV_HYP_PAGE_SIZE); 273 + memset(vmbus_connection.monitor_pages[1], 0x00, 274 + HV_HYP_PAGE_SIZE); 275 + 276 + } 277 + 222 278 msginfo = kzalloc(sizeof(*msginfo) + 223 279 sizeof(struct vmbus_channel_initiate_contact), 224 280 GFP_KERNEL); ··· 365 303 vmbus_connection.int_page = NULL; 366 304 } 367 305 368 - hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); 369 - hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); 370 - vmbus_connection.monitor_pages[0] = NULL; 371 - vmbus_connection.monitor_pages[1] = NULL; 306 + if (hv_is_isolation_supported()) { 307 + /* 308 + * memunmap() checks input address is ioremap address or not 309 + * inside. It doesn't unmap any thing in the non-SNP CVM and 310 + * so not check CVM type here. 311 + */ 312 + memunmap(vmbus_connection.monitor_pages[0]); 313 + memunmap(vmbus_connection.monitor_pages[1]); 314 + 315 + set_memory_encrypted((unsigned long) 316 + vmbus_connection.monitor_pages_original[0], 317 + 1); 318 + set_memory_encrypted((unsigned long) 319 + vmbus_connection.monitor_pages_original[1], 320 + 1); 321 + } 322 + 323 + hv_free_hyperv_page((unsigned long) 324 + vmbus_connection.monitor_pages_original[0]); 325 + hv_free_hyperv_page((unsigned long) 326 + vmbus_connection.monitor_pages_original[1]); 327 + vmbus_connection.monitor_pages_original[0] = 328 + vmbus_connection.monitor_pages[0] = NULL; 329 + vmbus_connection.monitor_pages_original[1] = 330 + vmbus_connection.monitor_pages[1] = NULL; 372 331 } 373 332 374 333 /* ··· 530 447 531 448 ++channel->sig_events; 532 449 533 - hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event); 450 + if (hv_isolation_type_snp()) 451 + hv_ghcb_hypercall(HVCALL_SIGNAL_EVENT, &channel->sig_event, 452 + NULL, sizeof(channel->sig_event)); 453 + else 454 + hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event); 534 455 } 535 456 EXPORT_SYMBOL_GPL(vmbus_set_event);
+65 -17
drivers/hv/hv.c
··· 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> ··· 98 97 aligned_msg->payload_size = payload_size; 99 98 memcpy((void *)aligned_msg->payload, payload, payload_size); 100 99 101 - status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); 100 + if (hv_isolation_type_snp()) 101 + status = hv_ghcb_hypercall(HVCALL_POST_MESSAGE, 102 + (void *)aligned_msg, NULL, 103 + sizeof(*aligned_msg)); 104 + else 105 + status = hv_do_hypercall(HVCALL_POST_MESSAGE, 106 + aligned_msg, NULL); 102 107 103 108 /* Preemption must remain disabled until after the hypercall 104 109 * so some other thread can't get scheduled onto this cpu and ··· 143 136 tasklet_init(&hv_cpu->msg_dpc, 144 137 vmbus_on_msg_dpc, (unsigned long) hv_cpu); 145 138 146 - hv_cpu->synic_message_page = 147 - (void *)get_zeroed_page(GFP_ATOMIC); 148 - if (hv_cpu->synic_message_page == NULL) { 149 - pr_err("Unable to allocate SYNIC message page\n"); 150 - goto err; 151 - } 139 + /* 140 + * Synic message and event pages are allocated by paravisor. 141 + * Skip these pages allocation here. 142 + */ 143 + if (!hv_isolation_type_snp()) { 144 + hv_cpu->synic_message_page = 145 + (void *)get_zeroed_page(GFP_ATOMIC); 146 + if (hv_cpu->synic_message_page == NULL) { 147 + pr_err("Unable to allocate SYNIC message page\n"); 148 + goto err; 149 + } 152 150 153 - hv_cpu->synic_event_page = (void *)get_zeroed_page(GFP_ATOMIC); 154 - if (hv_cpu->synic_event_page == NULL) { 155 - pr_err("Unable to allocate SYNIC event page\n"); 156 - goto err; 151 + hv_cpu->synic_event_page = 152 + (void *)get_zeroed_page(GFP_ATOMIC); 153 + if (hv_cpu->synic_event_page == NULL) { 154 + pr_err("Unable to allocate SYNIC event page\n"); 155 + goto err; 156 + } 157 157 } 158 158 159 159 hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); ··· 215 201 /* Setup the Synic's message page */ 216 202 simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); 217 203 simp.simp_enabled = 1; 218 - simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) 219 - >> HV_HYP_PAGE_SHIFT; 204 + 205 + if (hv_isolation_type_snp()) { 206 + hv_cpu->synic_message_page 207 + = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT, 208 + HV_HYP_PAGE_SIZE, MEMREMAP_WB); 209 + if (!hv_cpu->synic_message_page) 210 + pr_err("Fail to map syinc message page.\n"); 211 + } else { 212 + simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) 213 + >> HV_HYP_PAGE_SHIFT; 214 + } 220 215 221 216 hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); 222 217 223 218 /* Setup the Synic's event page */ 224 219 siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); 225 220 siefp.siefp_enabled = 1; 226 - siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) 227 - >> HV_HYP_PAGE_SHIFT; 221 + 222 + if (hv_isolation_type_snp()) { 223 + hv_cpu->synic_event_page = 224 + memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT, 225 + HV_HYP_PAGE_SIZE, MEMREMAP_WB); 226 + 227 + if (!hv_cpu->synic_event_page) 228 + pr_err("Fail to map syinc event page.\n"); 229 + } else { 230 + siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) 231 + >> HV_HYP_PAGE_SHIFT; 232 + } 228 233 229 234 hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); 230 235 ··· 290 257 */ 291 258 void hv_synic_disable_regs(unsigned int cpu) 292 259 { 260 + struct hv_per_cpu_context *hv_cpu 261 + = per_cpu_ptr(hv_context.cpu_context, cpu); 293 262 union hv_synic_sint shared_sint; 294 263 union hv_synic_simp simp; 295 264 union hv_synic_siefp siefp; ··· 308 273 shared_sint.as_uint64); 309 274 310 275 simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP); 276 + /* 277 + * In Isolation VM, sim and sief pages are allocated by 278 + * paravisor. These pages also will be used by kdump 279 + * kernel. So just reset enable bit here and keep page 280 + * addresses. 281 + */ 311 282 simp.simp_enabled = 0; 312 - simp.base_simp_gpa = 0; 283 + if (hv_isolation_type_snp()) 284 + memunmap(hv_cpu->synic_message_page); 285 + else 286 + simp.base_simp_gpa = 0; 313 287 314 288 hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); 315 289 316 290 siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP); 317 291 siefp.siefp_enabled = 0; 318 - siefp.base_siefp_gpa = 0; 292 + 293 + if (hv_isolation_type_snp()) 294 + memunmap(hv_cpu->synic_event_page); 295 + else 296 + siefp.base_siefp_gpa = 0; 319 297 320 298 hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); 321 299
+12
drivers/hv/hv_common.c
··· 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 } ··· 289 283 { 290 284 } 291 285 EXPORT_SYMBOL_GPL(hyperv_cleanup); 286 + 287 + u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size) 288 + { 289 + return HV_STATUS_INVALID_PARAMETER; 290 + } 291 + EXPORT_SYMBOL_GPL(hv_ghcb_hypercall);
+2
drivers/hv/hyperv_vmbus.h
··· 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
+44 -13
drivers/hv/ring_buffer.c
··· 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 ··· 185 183 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, 186 184 struct page *pages, u32 page_cnt, u32 max_pkt_size) 187 185 { 188 - int i; 189 186 struct page **pages_wraparound; 187 + unsigned long *pfns_wraparound; 188 + u64 pfn; 189 + int i; 190 190 191 191 BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); 192 192 ··· 196 192 * First page holds struct hv_ring_buffer, do wraparound mapping for 197 193 * the rest. 198 194 */ 199 - pages_wraparound = kcalloc(page_cnt * 2 - 1, sizeof(struct page *), 200 - GFP_KERNEL); 201 - if (!pages_wraparound) 202 - return -ENOMEM; 195 + if (hv_isolation_type_snp()) { 196 + pfn = page_to_pfn(pages) + 197 + PFN_DOWN(ms_hyperv.shared_gpa_boundary); 203 198 204 - pages_wraparound[0] = pages; 205 - for (i = 0; i < 2 * (page_cnt - 1); i++) 206 - pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1]; 199 + pfns_wraparound = kcalloc(page_cnt * 2 - 1, 200 + sizeof(unsigned long), GFP_KERNEL); 201 + if (!pfns_wraparound) 202 + return -ENOMEM; 207 203 208 - ring_info->ring_buffer = (struct hv_ring_buffer *) 209 - vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL); 204 + pfns_wraparound[0] = pfn; 205 + for (i = 0; i < 2 * (page_cnt - 1); i++) 206 + pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1; 210 207 211 - kfree(pages_wraparound); 208 + ring_info->ring_buffer = (struct hv_ring_buffer *) 209 + vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, 210 + PAGE_KERNEL); 211 + kfree(pfns_wraparound); 212 212 213 + if (!ring_info->ring_buffer) 214 + return -ENOMEM; 213 215 214 - if (!ring_info->ring_buffer) 215 - return -ENOMEM; 216 + /* Zero ring buffer after setting memory host visibility. */ 217 + memset(ring_info->ring_buffer, 0x00, PAGE_SIZE * page_cnt); 218 + } else { 219 + pages_wraparound = kcalloc(page_cnt * 2 - 1, 220 + sizeof(struct page *), 221 + GFP_KERNEL); 222 + if (!pages_wraparound) 223 + return -ENOMEM; 224 + 225 + pages_wraparound[0] = pages; 226 + for (i = 0; i < 2 * (page_cnt - 1); i++) 227 + pages_wraparound[i + 1] = 228 + &pages[i % (page_cnt - 1) + 1]; 229 + 230 + ring_info->ring_buffer = (struct hv_ring_buffer *) 231 + vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, 232 + PAGE_KERNEL); 233 + 234 + kfree(pages_wraparound); 235 + if (!ring_info->ring_buffer) 236 + return -ENOMEM; 237 + } 238 + 216 239 217 240 ring_info->ring_buffer->read_index = 218 241 ring_info->ring_buffer->write_index = 0;
+3 -2
drivers/net/hyperv/hyperv_net.h
··· 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;
+7 -8
drivers/net/hyperv/netvsc.c
··· 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 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 ··· 299 300 { 300 301 int ret; 301 302 302 - if (net_device->send_buf_gpadl_handle) { 303 + if (net_device->send_buf_gpadl_handle.gpadl_handle) { 303 304 ret = vmbus_teardown_gpadl(device->channel, 304 - net_device->send_buf_gpadl_handle); 305 + &net_device->send_buf_gpadl_handle); 305 306 306 307 /* If we failed here, we might as well return and have a leak 307 308 * rather than continue and a bugchk ··· 311 312 "unable to teardown send buffer's gpadl\n"); 312 313 return; 313 314 } 314 - net_device->send_buf_gpadl_handle = 0; 315 315 } 316 316 } 317 317 ··· 378 380 memset(init_packet, 0, sizeof(struct nvsp_message)); 379 381 init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; 380 382 init_packet->msg.v1_msg.send_recv_buf. 381 - gpadl_handle = net_device->recv_buf_gpadl_handle; 383 + gpadl_handle = net_device->recv_buf_gpadl_handle.gpadl_handle; 382 384 init_packet->msg.v1_msg. 383 385 send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; 384 386 ··· 461 463 ret = -ENOMEM; 462 464 goto cleanup; 463 465 } 466 + net_device->send_buf_size = buf_size; 464 467 465 468 /* Establish the gpadl handle for this buffer on this 466 469 * channel. Note: This call uses the vmbus connection rather ··· 481 482 memset(init_packet, 0, sizeof(struct nvsp_message)); 482 483 init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; 483 484 init_packet->msg.v1_msg.send_send_buf.gpadl_handle = 484 - net_device->send_buf_gpadl_handle; 485 + net_device->send_buf_gpadl_handle.gpadl_handle; 485 486 init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; 486 487 487 488 trace_nvsp_send(ndev, init_packet);
+8 -10
drivers/uio/uio_hv_generic.c
··· 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 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 } ··· 301 303 302 304 /* put Global Physical Address Label in name */ 303 305 snprintf(pdata->recv_name, sizeof(pdata->recv_name), 304 - "recv:%u", pdata->recv_gpadl); 306 + "recv:%u", pdata->recv_gpadl.gpadl_handle); 305 307 pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; 306 308 pdata->info.mem[RECV_BUF_MAP].addr 307 309 = (uintptr_t)pdata->recv_buf; ··· 322 324 } 323 325 324 326 snprintf(pdata->send_name, sizeof(pdata->send_name), 325 - "send:%u", pdata->send_gpadl); 327 + "send:%u", pdata->send_gpadl.gpadl_handle); 326 328 pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; 327 329 pdata->info.mem[SEND_BUF_MAP].addr 328 330 = (uintptr_t)pdata->send_buf;
+1
include/asm-generic/hyperv-tlfs.h
··· 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
+19 -1
include/asm-generic/mshyperv.h
··· 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 ··· 54 44 55 45 extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 56 46 extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 47 + extern bool hv_isolation_type_snp(void); 57 48 58 49 /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ 59 50 static inline int hv_result(u64 status) ··· 265 254 bool hv_is_hibernation_supported(void); 266 255 enum hv_isolation_type hv_get_isolation_type(void); 267 256 bool hv_is_isolation_supported(void); 257 + bool hv_isolation_type_snp(void); 258 + u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 268 259 void hyperv_cleanup(void); 269 260 bool hv_query_ext_cap(u64 cap_query); 270 261 #else /* CONFIG_HYPERV */ 271 262 static inline bool hv_is_hyperv_initialized(void) { return false; } 272 263 static inline bool hv_is_hibernation_supported(void) { return false; } 273 264 static inline void hyperv_cleanup(void) {} 265 + static inline bool hv_is_isolation_supported(void) { return false; } 266 + static inline enum hv_isolation_type hv_get_isolation_type(void) 267 + { 268 + return HV_ISOLATION_TYPE_NONE; 269 + } 274 270 #endif /* CONFIG_HYPERV */ 275 271 276 272 #endif
+9 -16
include/linux/hyperv.h
··· 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 ··· 828 822 bool rescind_ref; /* got rescind msg, got channel reference */ 829 823 struct completion rescind_event; 830 824 831 - u32 ringbuffer_gpadlhandle; 825 + struct vmbus_gpadl ringbuffer_gpadlhandle; 832 826 833 827 /* Allocated memory for ring buffer */ 834 828 struct page *ringbuffer_page; ··· 1106 1100 void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel, 1107 1101 void (*chn_rescind_cb)(struct vmbus_channel *)); 1108 1102 1109 - /* 1110 - * Check if sub-channels have already been offerred. This API will be useful 1111 - * when the driver is unloaded after establishing sub-channels. In this case, 1112 - * when the driver is re-loaded, the driver would have to check if the 1113 - * subchannels have already been established before attempting to request 1114 - * the creation of sub-channels. 1115 - * This function returns TRUE to indicate that subchannels have already been 1116 - * created. 1117 - * This function should be invoked after setting the callback function for 1118 - * sub-channel creation. 1119 - */ 1120 - bool vmbus_are_subchannels_present(struct vmbus_channel *primary); 1121 - 1122 1103 /* The format must be the same as struct vmdata_gpa_direct */ 1123 1104 struct vmbus_channel_packet_page_buffer { 1124 1105 u16 type; ··· 1185 1192 extern int vmbus_establish_gpadl(struct vmbus_channel *channel, 1186 1193 void *kbuffer, 1187 1194 u32 size, 1188 - u32 *gpadl_handle); 1195 + struct vmbus_gpadl *gpadl); 1189 1196 1190 1197 extern int vmbus_teardown_gpadl(struct vmbus_channel *channel, 1191 - u32 gpadl_handle); 1198 + struct vmbus_gpadl *gpadl); 1192 1199 1193 1200 void vmbus_reset_channel_cb(struct vmbus_channel *channel); 1194 1201