History

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

Linus Torvalds committed 5 years ago

Commit 44261f82 parents 0aaa58e 285f68a21 files · +761 −172Browse files

Unified · Split

21 files
  1. arch/x86/hyperv/Makefile +1 −1
  2. arch/x86/hyperv/hv_init.c +61 −21
  3. arch/x86/hyperv/ivm.c +289 −0
  4. arch/x86/include/asm/hyperv-tlfs.h +17 −0
  5. arch/x86/include/asm/mshyperv.h +57 −13
  6. arch/x86/kernel/cpu/mshyperv.c +5 −0
  7. arch/x86/mm/pat/set_memory.c +18 −5
  8. drivers/hv/Kconfig +1 −0
  9. drivers/hv/channel.c +48 −24
  10. drivers/hv/channel_mgmt.c +0 −34
  11. drivers/hv/connection.c +94 −7
  12. drivers/hv/hv.c +65 −17
  13. drivers/hv/hv_common.c +12 −0
  14. drivers/hv/hyperv_vmbus.h +2 −0
  15. drivers/hv/ring_buffer.c +44 −13
  16. drivers/net/hyperv/hyperv_net.h +3 −2
  17. drivers/net/hyperv/netvsc.c +7 −8
  18. drivers/uio/uio_hv_generic.c +8 −10
  19. include/asm-generic/hyperv-tlfs.h +1 −0
  20. include/asm-generic/mshyperv.h +19 −1
  21. include/linux/hyperv.h +9 −16
arch/x86/hyperv/Makefile+1−1
@@ -1,5 +1,5 @@
11 # 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
33 obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o
44
55 ifdef CONFIG_X86_64
arch/x86/hyperv/hv_init.c+61−21
@@ -36,12 +36,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id); · 35 unmodified lines
3636 void *hv_hypercall_pg;
3737 EXPORT_SYMBOL_GPL(hv_hypercall_pg);
3838
39+union hv_ghcb __percpu **hv_ghcb_pg;
40+
3941 /* Storage to save the hypercall page temporarily for hibernation */
4042 static void *hv_hypercall_pg_saved;
4143
4244 struct hv_vp_assist_page **hv_vp_assist_page;
4345 EXPORT_SYMBOL_GPL(hv_vp_assist_page);
4446
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+
4575 static int hv_cpu_init(unsigned int cpu)
4676 {
4777 union hv_vp_assist_msr_contents msr = { 0 };
@@ -85,7 +115,7 @@ static int hv_cpu_init(unsigned int cpu) · 37 unmodified lines
85115 }
86116 }
87117
88− return 0;
118+ return hyperv_init_ghcb();
89119 }
90120
91121 static void (*hv_reenlightenment_cb)(void);
@@ -139,7 +169,6 @@ void set_hv_tscchange_cb(void (*cb)(void)) · 47 unmodified lines
139169 struct hv_reenlightenment_control re_ctrl = {
140170 .vector = HYPERV_REENLIGHTENMENT_VECTOR,
141171 .enabled = 1,
142− .target_vp = hv_vp_index[smp_processor_id()]
143172 };
144173 struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
145174
@@ -153,8 +182,12 @@ void set_hv_tscchange_cb(void (*cb)(void)) · 7 unmodified lines
153182 /* Make sure callback is registered before we write to MSRs */
154183 wmb();
155184
185+ re_ctrl.target_vp = hv_vp_index[get_cpu()];
186+
156187 wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
157188 wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl));
189+
190+ put_cpu();
158191 }
159192 EXPORT_SYMBOL_GPL(set_hv_tscchange_cb);
160193
@@ -177,6 +210,14 @@ static int hv_cpu_die(unsigned int cpu) · 16 unmodified lines
177210 {
178211 struct hv_reenlightenment_control re_ctrl;
179212 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+ }
180221
181222 hv_common_cpu_die(cpu);
182223
@@ -366,10 +407,16 @@ void __init hyperv_init(void) · 183 unmodified lines
366407 goto common_free;
367408 }
368409
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+
369416 cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
370417 hv_cpu_init, hv_cpu_die);
371418 if (cpuhp < 0)
372− goto free_vp_assist_page;
419+ goto free_ghcb_page;
373420
374421 /*
375422 * Setup the hypercall page and enable hypercalls.
@@ -379,14 +426,15 @@ void __init hyperv_init(void) · 3 unmodified lines
379426 guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
380427 wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
381428
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+
382432 hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START,
383433 VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
384434 VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
385435 __builtin_return_address(0));
386− if (hv_hypercall_pg == NULL) {
387− wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
388− goto remove_cpuhp_state;
389− }
436+ if (hv_hypercall_pg == NULL)
437+ goto clean_guest_os_id;
390438
391439 rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
392440 hypercall_msr.enable = 1;
@@ -456,8 +504,12 @@ void __init hyperv_init(void) · 63 unmodified lines
456504 hv_query_ext_cap(0);
457505 return;
458506
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);
460510 cpuhp_remove_state(cpuhp);
511+free_ghcb_page:
512+ free_percpu(hv_ghcb_pg);
461513 free_vp_assist_page:
462514 kfree(hv_vp_assist_page);
463515 hv_vp_assist_page = NULL;
@@ -476,6 +528,7 @@ void hyperv_cleanup(void) · 12 unmodified lines
476528
477529 /* Reset our OS id */
478530 wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
531+ hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0);
479532
480533 /*
481534 * Reset hypercall page reference before reset the page,
@@ -546,16 +599,3 @@ bool hv_is_hyperv_initialized(void) · 64 unmodified lines
546599 return hypercall_msr.enable;
547600 }
548601 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−}
arch/x86/hyperv/ivm.c+289−0
@@ -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+}
arch/x86/include/asm/hyperv-tlfs.h+17−0
@@ -276,6 +276,23 @@ enum hv_isolation_type { · 275 unmodified lines
276276 #define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT
277277 #define HV_X64_MSR_REFERENCE_TSC HV_REGISTER_REFERENCE_TSC
278278
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+
279296 /*
280297 * Declare the MSR used to setup pages used to communicate with the hypervisor.
281298 */
arch/x86/include/asm/mshyperv.h+57−13
@@ -11,23 +11,14 @@ · 10 unmodified lines
1111 #include <asm/paravirt.h>
1212 #include <asm/mshyperv.h>
1313
14+union hv_ghcb;
15+
16+DECLARE_STATIC_KEY_FALSE(isolation_type_snp);
17+
1418 typedef int (*hyperv_fill_flush_list_func)(
1519 struct hv_guest_mapping_flush_list *flush,
1620 void *data);
1721
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−
3122 #define hv_get_raw_timer() rdtsc_ordered()
3223
3324 void hyperv_vector_handler(struct pt_regs *regs);
@@ -39,6 +30,8 @@ extern void *hv_hypercall_pg; · 5 unmodified lines
3930
4031 extern u64 hv_current_partition_id;
4132
33+extern union hv_ghcb __percpu **hv_ghcb_pg;
34+
4235 int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
4336 int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
4437 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
188181 int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector,
189182 struct hv_interrupt_entry *entry);
190183 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+}
191228
192229 #else /* CONFIG_HYPERV */
193230 static inline void hyperv_init(void) {}
@@ -205,6 +242,13 @@ static inline int hyperv_flush_guest_mapping_range(u64 as, · 11 unmodified lines
205242 {
206243 return -1;
207244 }
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+}
208252 #endif /* CONFIG_HYPERV */
209253
210254
arch/x86/kernel/cpu/mshyperv.c+5−0
@@ -313,9 +313,14 @@ static void __init ms_hyperv_init_platform(void) · 312 unmodified lines
313313 if (ms_hyperv.priv_high & HV_ISOLATION) {
314314 ms_hyperv.isolation_config_a = cpuid_eax(HYPERV_CPUID_ISOLATION_CONFIG);
315315 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);
316318
317319 pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n",
318320 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);
319324 }
320325
321326 if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) {
arch/x86/mm/pat/set_memory.c+18−5
@@ -30,6 +30,8 @@ · 29 unmodified lines
3030 #include <asm/proto.h>
3131 #include <asm/memtype.h>
3232 #include <asm/set_memory.h>
33+#include <asm/hyperv-tlfs.h>
34+#include <asm/mshyperv.h>
3335
3436 #include "../mm_internal.h"
3537
@@ -1981,15 +1983,15 @@ int set_memory_global(unsigned long addr, int numpages) · 1945 unmodified lines
19811983 __pgprot(_PAGE_GLOBAL), 0);
19821984 }
19831985
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)
19851991 {
19861992 struct cpa_data cpa;
19871993 int ret;
19881994
1989− /* Nothing to do if memory encryption is not active */
1990− if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT))
1991− return 0;
1992−
19931995 /* Should not be working on unaligned addresses */
19941996 if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr))
19951997 addr &= PAGE_MASK;
@@ -2024,6 +2026,17 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) · 28 unmodified lines
20242026 return ret;
20252027 }
20262028
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+
20272040 int set_memory_encrypted(unsigned long addr, int numpages)
20282041 {
20292042 return __set_memory_enc_dec(addr, numpages, true);
drivers/hv/Kconfig+1−0
@@ -8,6 +8,7 @@ config HYPERV · 7 unmodified lines
88 || (ARM64 && !CPU_BIG_ENDIAN))
99 select PARAVIRT
1010 select X86_HV_CALLBACK_VECTOR if X86
11+ select VMAP_PFN
1112 help
1213 Select this option to run Linux as a Hyper-V client operating
1314 system.
drivers/hv/channel.c+48−24
@@ -17,6 +17,7 @@ · 16 unmodified lines
1717 #include <linux/hyperv.h>
1818 #include <linux/uio.h>
1919 #include <linux/interrupt.h>
20+#include <linux/set_memory.h>
2021 #include <asm/page.h>
2122 #include <asm/mshyperv.h>
2223
@@ -456,7 +457,7 @@ nomem: · 433 unmodified lines
456457 static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
457458 enum hv_gpadl_type type, void *kbuffer,
458459 u32 size, u32 send_offset,
459− u32 *gpadl_handle)
460+ struct vmbus_gpadl *gpadl)
460461 {
461462 struct vmbus_channel_gpadl_header *gpadlmsg;
462463 struct vmbus_channel_gpadl_body *gpadl_body;
@@ -474,6 +475,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, · 11 unmodified lines
474475 if (ret)
475476 return ret;
476477
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+
477487 init_completion(&msginfo->waitevent);
478488 msginfo->waiting_channel = channel;
479489
@@ -537,7 +547,10 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, · 57 unmodified lines
537547 }
538548
539549 /* 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+
541554
542555 cleanup:
543556 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
@@ -549,6 +562,11 @@ cleanup: · 5 unmodified lines
549562 }
550563
551564 kfree(msginfo);
565+
566+ if (ret)
567+ set_memory_encrypted((unsigned long)kbuffer,
568+ PFN_UP(size));
569+
552570 return ret;
553571 }
554572
@@ -561,10 +579,10 @@ cleanup: · 6 unmodified lines
561579 * @gpadl_handle: some funky thing
562580 */
563581 int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
564− u32 size, u32 *gpadl_handle)
582+ u32 size, struct vmbus_gpadl *gpadl)
565583 {
566584 return __vmbus_establish_gpadl(channel, HV_GPADL_BUFFER, kbuffer, size,
567− 0U, gpadl_handle);
585+ 0U, gpadl);
568586 }
569587 EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
570588
@@ -665,17 +683,8 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 94 unmodified lines
665683 if (!newchannel->max_pkt_size)
666684 newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE;
667685
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−
677686 /* Establish the gpadl for the ring buffer */
678− newchannel->ringbuffer_gpadlhandle = 0;
687+ newchannel->ringbuffer_gpadlhandle.gpadl_handle = 0;
679688
680689 err = __vmbus_establish_gpadl(newchannel, HV_GPADL_RING,
681690 page_address(newchannel->ringbuffer_page),
@@ -685,6 +694,16 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 3 unmodified lines
685694 if (err)
686695 goto error_clean_ring;
687696
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+
688707 /* Create and init the channel open message */
689708 open_info = kzalloc(sizeof(*open_info) +
690709 sizeof(struct vmbus_channel_open_channel),
@@ -701,7 +720,8 @@ static int __vmbus_open(struct vmbus_channel *newchannel, · 10 unmodified lines
701720 open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL;
702721 open_msg->openid = newchannel->offermsg.child_relid;
703722 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;
705725 /*
706726 * The unit of ->downstream_ringbuffer_pageoffset is HV_HYP_PAGE and
707727 * the unit of ->ringbuffer_send_offset (i.e. send_pages) is PAGE, so
@@ -759,8 +779,7 @@ error_clean_msglist: · 51 unmodified lines
759779 error_free_info:
760780 kfree(open_info);
761781 error_free_gpadl:
762− vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
763− newchannel->ringbuffer_gpadlhandle = 0;
782+ vmbus_teardown_gpadl(newchannel, &newchannel->ringbuffer_gpadlhandle);
764783 error_clean_ring:
765784 hv_ringbuffer_cleanup(&newchannel->outbound);
766785 hv_ringbuffer_cleanup(&newchannel->inbound);
@@ -806,7 +825,7 @@ EXPORT_SYMBOL_GPL(vmbus_open); · 39 unmodified lines
806825 /*
807826 * vmbus_teardown_gpadl -Teardown the specified GPADL handle
808827 */
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)
810829 {
811830 struct vmbus_channel_gpadl_teardown *msg;
812831 struct vmbus_channel_msginfo *info;
@@ -825,7 +844,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) · 12 unmodified lines
825844
826845 msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
827846 msg->child_relid = channel->offermsg.child_relid;
828− msg->gpadl = gpadl_handle;
847+ msg->gpadl = gpadl->gpadl_handle;
829848
830849 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
831850 list_add_tail(&info->msglistentry,
@@ -845,6 +864,8 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) · 13 unmodified lines
845864
846865 wait_for_completion(&info->waitevent);
847866
867+ gpadl->gpadl_handle = 0;
868+
848869 post_msg_err:
849870 /*
850871 * If the channel has been rescinded;
@@ -859,6 +880,12 @@ post_msg_err: · 8 unmodified lines
859880 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
860881
861882 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+
862889 return ret;
863890 }
864891 EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
@@ -933,9 +960,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel) · 68 unmodified lines
933960 }
934961
935962 /* Tear down the gpadl for the channel's ring buffer */
936− else if (channel->ringbuffer_gpadlhandle) {
937− ret = vmbus_teardown_gpadl(channel,
938− channel->ringbuffer_gpadlhandle);
963+ else if (channel->ringbuffer_gpadlhandle.gpadl_handle) {
964+ ret = vmbus_teardown_gpadl(channel, &channel->ringbuffer_gpadlhandle);
939965 if (ret) {
940966 pr_err("Close failed: teardown gpadl return %d\n", ret);
941967 /*
@@ -943,8 +969,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel) · 1 unmodified line
943969 * it is perhaps better to leak memory.
944970 */
945971 }
946−
947− channel->ringbuffer_gpadlhandle = 0;
948972 }
949973
950974 if (!ret)
drivers/hv/channel_mgmt.c+0−34
@@ -1581,21 +1581,6 @@ cleanup: · 1580 unmodified lines
15811581 return ret;
15821582 }
15831583
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−
15991584 void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel,
16001585 void (*sc_cr_cb)(struct vmbus_channel *new_sc))
16011586 {
@@ -1603,25 +1588,6 @@ void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, · 1 unmodified line
16031588 }
16041589 EXPORT_SYMBOL_GPL(vmbus_set_sc_create_callback);
16051590
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−
16251591 void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel,
16261592 void (*chn_rescind_cb)(struct vmbus_channel *))
16271593 {
drivers/hv/connection.c+94−7
@@ -19,6 +19,8 @@ · 18 unmodified lines
1919 #include <linux/vmalloc.h>
2020 #include <linux/hyperv.h>
2121 #include <linux/export.h>
22+#include <linux/io.h>
23+#include <linux/set_memory.h>
2224 #include <asm/mshyperv.h>
2325
2426 #include "hyperv_vmbus.h"
@@ -102,8 +104,9 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) · 77 unmodified lines
102104 vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
103105 }
104106
105− msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
106− msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
107+ msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0];
108+ msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1];
109+
107110 msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU);
108111
109112 /*
@@ -216,6 +219,65 @@ int vmbus_connect(void) · 106 unmodified lines
216219 goto cleanup;
217220 }
218221
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+
219281 msginfo = kzalloc(sizeof(*msginfo) +
220282 sizeof(struct vmbus_channel_initiate_contact),
221283 GFP_KERNEL);
@@ -303,10 +365,31 @@ void vmbus_disconnect(void) · 81 unmodified lines
303365 vmbus_connection.int_page = NULL;
304366 }
305367
306− hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]);
307− hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]);
308− vmbus_connection.monitor_pages[0] = NULL;
309− vmbus_connection.monitor_pages[1] = NULL;
368+ if (hv_is_isolation_supported()) {
369+ /*
370+ * memunmap() checks input address is ioremap address or not
371+ * inside. It doesn't unmap any thing in the non-SNP CVM and
372+ * so not check CVM type here.
373+ */
374+ memunmap(vmbus_connection.monitor_pages[0]);
375+ memunmap(vmbus_connection.monitor_pages[1]);
376+
377+ set_memory_encrypted((unsigned long)
378+ vmbus_connection.monitor_pages_original[0],
379+ 1);
380+ set_memory_encrypted((unsigned long)
381+ vmbus_connection.monitor_pages_original[1],
382+ 1);
383+ }
384+
385+ hv_free_hyperv_page((unsigned long)
386+ vmbus_connection.monitor_pages_original[0]);
387+ hv_free_hyperv_page((unsigned long)
388+ vmbus_connection.monitor_pages_original[1]);
389+ vmbus_connection.monitor_pages_original[0] =
390+ vmbus_connection.monitor_pages[0] = NULL;
391+ vmbus_connection.monitor_pages_original[1] =
392+ vmbus_connection.monitor_pages[1] = NULL;
310393 }
311394
312395 /*
@@ -447,6 +530,10 @@ void vmbus_set_event(struct vmbus_channel *channel) · 134 unmodified lines
447530
448531 ++channel->sig_events;
449532
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);
451538 }
452539 EXPORT_SYMBOL_GPL(vmbus_set_event);
drivers/hv/hv.c+65−17
@@ -8,6 +8,7 @@ · 7 unmodified lines
88 */
99 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1010
11+#include <linux/io.h>
1112 #include <linux/kernel.h>
1213 #include <linux/mm.h>
1314 #include <linux/slab.h>
@@ -97,7 +98,13 @@ int hv_post_message(union hv_connection_id connection_id, · 83 unmodified lines
9798 aligned_msg->payload_size = payload_size;
9899 memcpy((void *)aligned_msg->payload, payload, payload_size);
99100
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);
101108
102109 /* Preemption must remain disabled until after the hypercall
103110 * so some other thread can't get scheduled onto this cpu and
@@ -136,17 +143,24 @@ int hv_synic_alloc(void) · 32 unmodified lines
136143 tasklet_init(&hv_cpu->msg_dpc,
137144 vmbus_on_msg_dpc, (unsigned long) hv_cpu);
138145
139− hv_cpu->synic_message_page =
140− (void *)get_zeroed_page(GFP_ATOMIC);
141− if (hv_cpu->synic_message_page == NULL) {
142− pr_err("Unable to allocate SYNIC message page\n");
143− goto err;
144− }
146+ /*
147+ * Synic message and event pages are allocated by paravisor.
148+ * Skip these pages allocation here.
149+ */
150+ if (!hv_isolation_type_snp()) {
151+ hv_cpu->synic_message_page =
152+ (void *)get_zeroed_page(GFP_ATOMIC);
153+ if (hv_cpu->synic_message_page == NULL) {
154+ pr_err("Unable to allocate SYNIC message page\n");
155+ goto err;
156+ }
145157
146− hv_cpu->synic_event_page = (void *)get_zeroed_page(GFP_ATOMIC);
147− if (hv_cpu->synic_event_page == NULL) {
148− pr_err("Unable to allocate SYNIC event page\n");
149− goto err;
158+ hv_cpu->synic_event_page =
159+ (void *)get_zeroed_page(GFP_ATOMIC);
160+ if (hv_cpu->synic_event_page == NULL) {
161+ pr_err("Unable to allocate SYNIC event page\n");
162+ goto err;
163+ }
150164 }
151165
152166 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
201215 /* Setup the Synic's message page */
202216 simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP);
203217 simp.simp_enabled = 1;
204− simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page)
205− >> HV_HYP_PAGE_SHIFT;
218+
219+ if (hv_isolation_type_snp()) {
220+ hv_cpu->synic_message_page
221+ = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
222+ HV_HYP_PAGE_SIZE, MEMREMAP_WB);
223+ if (!hv_cpu->synic_message_page)
224+ pr_err("Fail to map syinc message page.\n");
225+ } else {
226+ simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page)
227+ >> HV_HYP_PAGE_SHIFT;
228+ }
206229
207230 hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
208231
209232 /* Setup the Synic's event page */
210233 siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
211234 siefp.siefp_enabled = 1;
212− siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page)
213− >> HV_HYP_PAGE_SHIFT;
235+
236+ if (hv_isolation_type_snp()) {
237+ hv_cpu->synic_event_page =
238+ memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT,
239+ HV_HYP_PAGE_SIZE, MEMREMAP_WB);
240+
241+ if (!hv_cpu->synic_event_page)
242+ pr_err("Fail to map syinc event page.\n");
243+ } else {
244+ siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page)
245+ >> HV_HYP_PAGE_SHIFT;
246+ }
214247
215248 hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);
216249
@@ -257,6 +290,8 @@ int hv_synic_init(unsigned int cpu) · 40 unmodified lines
257290 */
258291 void hv_synic_disable_regs(unsigned int cpu)
259292 {
293+ struct hv_per_cpu_context *hv_cpu
294+ = per_cpu_ptr(hv_context.cpu_context, cpu);
260295 union hv_synic_sint shared_sint;
261296 union hv_synic_simp simp;
262297 union hv_synic_siefp siefp;
@@ -273,14 +308,27 @@ void hv_synic_disable_regs(unsigned int cpu) · 10 unmodified lines
273308 shared_sint.as_uint64);
274309
275310 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+ */
276317 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;
278322
279323 hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
280324
281325 siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
282326 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;
284332
285333 hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);
286334
drivers/hv/hv_common.c+12−0
@@ -249,6 +249,12 @@ bool __weak hv_is_isolation_supported(void) · 248 unmodified lines
249249 }
250250 EXPORT_SYMBOL_GPL(hv_is_isolation_supported);
251251
252+bool __weak hv_isolation_type_snp(void)
253+{
254+ return false;
255+}
256+EXPORT_SYMBOL_GPL(hv_isolation_type_snp);
257+
252258 void __weak hv_setup_vmbus_handler(void (*handler)(void))
253259 {
254260 }
@@ -283,3 +289,9 @@ void __weak hyperv_cleanup(void) · 28 unmodified lines
283289 {
284290 }
285291 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);
drivers/hv/hyperv_vmbus.h+2−0
@@ -241,6 +241,8 @@ struct vmbus_connection { · 240 unmodified lines
241241 * is child->parent notification
242242 */
243243 struct hv_monitor_page *monitor_pages[2];
244+ void *monitor_pages_original[2];
245+ phys_addr_t monitor_pages_pa[2];
244246 struct list_head chn_msg_list;
245247 spinlock_t channelmsg_lock;
246248
drivers/hv/ring_buffer.c+44−13
@@ -17,6 +17,8 @@ · 16 unmodified lines
1717 #include <linux/vmalloc.h>
1818 #include <linux/slab.h>
1919 #include <linux/prefetch.h>
20+#include <linux/io.h>
21+#include <asm/mshyperv.h>
2022
2123 #include "hyperv_vmbus.h"
2224
@@ -183,8 +185,10 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel) · 160 unmodified lines
183185 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
184186 struct page *pages, u32 page_cnt, u32 max_pkt_size)
185187 {
186− int i;
187188 struct page **pages_wraparound;
189+ unsigned long *pfns_wraparound;
190+ u64 pfn;
191+ int i;
188192
189193 BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE));
190194
@@ -192,23 +196,50 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, · 1 unmodified line
192196 * First page holds struct hv_ring_buffer, do wraparound mapping for
193197 * the rest.
194198 */
195− pages_wraparound = kcalloc(page_cnt * 2 - 1, sizeof(struct page *),
196− GFP_KERNEL);
197− if (!pages_wraparound)
198− return -ENOMEM;
199+ if (hv_isolation_type_snp()) {
200+ pfn = page_to_pfn(pages) +
201+ PFN_DOWN(ms_hyperv.shared_gpa_boundary);
202+
203+ pfns_wraparound = kcalloc(page_cnt * 2 - 1,
204+ sizeof(unsigned long), GFP_KERNEL);
205+ if (!pfns_wraparound)
206+ return -ENOMEM;
199207
200− pages_wraparound[0] = pages;
201− for (i = 0; i < 2 * (page_cnt - 1); i++)
202− pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1];
208+ pfns_wraparound[0] = pfn;
209+ for (i = 0; i < 2 * (page_cnt - 1); i++)
210+ pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1;
203211
204− ring_info->ring_buffer = (struct hv_ring_buffer *)
205− vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL);
212+ ring_info->ring_buffer = (struct hv_ring_buffer *)
213+ vmap_pfn(pfns_wraparound, page_cnt * 2 - 1,
214+ PAGE_KERNEL);
215+ kfree(pfns_wraparound);
206216
207− kfree(pages_wraparound);
217+ if (!ring_info->ring_buffer)
218+ return -ENOMEM;
208219
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+ }
209242
210− if (!ring_info->ring_buffer)
211− return -ENOMEM;
212243
213244 ring_info->ring_buffer->read_index =
214245 ring_info->ring_buffer->write_index = 0;
drivers/net/hyperv/hyperv_net.h+3−2
@@ -1075,14 +1075,15 @@ struct netvsc_device { · 1074 unmodified lines
10751075 /* Receive buffer allocated by us but manages by NetVSP */
10761076 void *recv_buf;
10771077 u32 recv_buf_size; /* allocated bytes */
1078− u32 recv_buf_gpadl_handle;
1078+ struct vmbus_gpadl recv_buf_gpadl_handle;
10791079 u32 recv_section_cnt;
10801080 u32 recv_section_size;
10811081 u32 recv_completion_cnt;
10821082
10831083 /* Send buffer allocated by us */
10841084 void *send_buf;
1085− u32 send_buf_gpadl_handle;
1085+ u32 send_buf_size;
1086+ struct vmbus_gpadl send_buf_gpadl_handle;
10861087 u32 send_section_cnt;
10871088 u32 send_section_size;
10881089 unsigned long *send_section_map;
drivers/net/hyperv/netvsc.c+7−8
@@ -278,9 +278,9 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device, · 277 unmodified lines
278278 {
279279 int ret;
280280
281− if (net_device->recv_buf_gpadl_handle) {
281+ if (net_device->recv_buf_gpadl_handle.gpadl_handle) {
282282 ret = vmbus_teardown_gpadl(device->channel,
283− net_device->recv_buf_gpadl_handle);
283+ &net_device->recv_buf_gpadl_handle);
284284
285285 /* If we failed here, we might as well return and have a leak
286286 * rather than continue and a bugchk
@@ -290,7 +290,6 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device, · 3 unmodified lines
290290 "unable to teardown receive buffer's gpadl\n");
291291 return;
292292 }
293− net_device->recv_buf_gpadl_handle = 0;
294293 }
295294 }
296295
@@ -300,9 +299,9 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device, · 3 unmodified lines
300299 {
301300 int ret;
302301
303− if (net_device->send_buf_gpadl_handle) {
302+ if (net_device->send_buf_gpadl_handle.gpadl_handle) {
304303 ret = vmbus_teardown_gpadl(device->channel,
305− net_device->send_buf_gpadl_handle);
304+ &net_device->send_buf_gpadl_handle);
306305
307306 /* If we failed here, we might as well return and have a leak
308307 * rather than continue and a bugchk
@@ -312,7 +311,6 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device, · 3 unmodified lines
312311 "unable to teardown send buffer's gpadl\n");
313312 return;
314313 }
315− net_device->send_buf_gpadl_handle = 0;
316314 }
317315 }
318316
@@ -380,7 +378,7 @@ static int netvsc_init_buf(struct hv_device *device, · 61 unmodified lines
380378 memset(init_packet, 0, sizeof(struct nvsp_message));
381379 init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF;
382380 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;
384382 init_packet->msg.v1_msg.
385383 send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
386384
@@ -463,6 +461,7 @@ static int netvsc_init_buf(struct hv_device *device, · 76 unmodified lines
463461 ret = -ENOMEM;
464462 goto cleanup;
465463 }
464+ net_device->send_buf_size = buf_size;
466465
467466 /* Establish the gpadl handle for this buffer on this
468467 * 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
482481 memset(init_packet, 0, sizeof(struct nvsp_message));
483482 init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF;
484483 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;
486485 init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID;
487486
488487 trace_nvsp_send(ndev, init_packet);
drivers/uio/uio_hv_generic.c+8−10
@@ -58,11 +58,11 @@ struct hv_uio_private_data { · 57 unmodified lines
5858 atomic_t refcnt;
5959
6060 void *recv_buf;
61− u32 recv_gpadl;
61+ struct vmbus_gpadl recv_gpadl;
6262 char recv_name[32]; /* "recv_4294967295" */
6363
6464 void *send_buf;
65− u32 send_gpadl;
65+ struct vmbus_gpadl send_gpadl;
6666 char send_name[32];
6767 };
6868
@@ -179,15 +179,13 @@ hv_uio_new_channel(struct vmbus_channel *new_sc) · 110 unmodified lines
179179 static void
180180 hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
181181 {
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);
185184 vfree(pdata->send_buf);
186185 }
187186
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);
191189 vfree(pdata->recv_buf);
192190 }
193191 }
@@ -303,7 +301,7 @@ hv_uio_probe(struct hv_device *dev, · 109 unmodified lines
303301
304302 /* put Global Physical Address Label in name */
305303 snprintf(pdata->recv_name, sizeof(pdata->recv_name),
306− "recv:%u", pdata->recv_gpadl);
304+ "recv:%u", pdata->recv_gpadl.gpadl_handle);
307305 pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name;
308306 pdata->info.mem[RECV_BUF_MAP].addr
309307 = (uintptr_t)pdata->recv_buf;
@@ -324,7 +322,7 @@ hv_uio_probe(struct hv_device *dev, · 14 unmodified lines
324322 }
325323
326324 snprintf(pdata->send_name, sizeof(pdata->send_name),
327− "send:%u", pdata->send_gpadl);
325+ "send:%u", pdata->send_gpadl.gpadl_handle);
328326 pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name;
329327 pdata->info.mem[SEND_BUF_MAP].addr
330328 = (uintptr_t)pdata->send_buf;
include/asm-generic/hyperv-tlfs.h+1−0
@@ -158,6 +158,7 @@ struct ms_hyperv_tsc_page { · 157 unmodified lines
158158 #define HVCALL_RETARGET_INTERRUPT 0x007e
159159 #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
160160 #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
161+#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db
161162
162163 /* Extended hypercalls */
163164 #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001
include/asm-generic/mshyperv.h+19−1
@@ -35,7 +35,17 @@ struct ms_hyperv_info { · 34 unmodified lines
3535 u32 max_vp_index;
3636 u32 max_lp_index;
3737 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;
3949 };
4050 extern struct ms_hyperv_info ms_hyperv;
4151
@@ -44,6 +54,7 @@ extern void __percpu **hyperv_pcpu_output_arg; · 2 unmodified lines
4454
4555 extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);
4656 extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
57+extern bool hv_isolation_type_snp(void);
4758
4859 /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */
4960 static inline int hv_result(u64 status)
@@ -254,12 +265,19 @@ bool hv_is_hyperv_initialized(void); · 204 unmodified lines
254265 bool hv_is_hibernation_supported(void);
255266 enum hv_isolation_type hv_get_isolation_type(void);
256267 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);
257270 void hyperv_cleanup(void);
258271 bool hv_query_ext_cap(u64 cap_query);
259272 #else /* CONFIG_HYPERV */
260273 static inline bool hv_is_hyperv_initialized(void) { return false; }
261274 static inline bool hv_is_hibernation_supported(void) { return false; }
262275 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+}
263281 #endif /* CONFIG_HYPERV */
264282
265283 #endif
include/linux/hyperv.h+9−16
@@ -803,6 +803,12 @@ struct vmbus_device { · 802 unmodified lines
803803
804804 #define VMBUS_DEFAULT_MAX_PKT_SIZE 4096
805805
806+struct vmbus_gpadl {
807+ u32 gpadl_handle;
808+ u32 size;
809+ void *buffer;
810+};
811+
806812 struct vmbus_channel {
807813 struct list_head listentry;
808814
@@ -822,7 +828,7 @@ struct vmbus_channel { · 13 unmodified lines
822828 bool rescind_ref; /* got rescind msg, got channel reference */
823829 struct completion rescind_event;
824830
825− u32 ringbuffer_gpadlhandle;
831+ struct vmbus_gpadl ringbuffer_gpadlhandle;
826832
827833 /* Allocated memory for ring buffer */
828834 struct page *ringbuffer_page;
@@ -1100,19 +1106,6 @@ void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel, · 271 unmodified lines
11001106 void vmbus_set_chn_rescind_callback(struct vmbus_channel *channel,
11011107 void (*chn_rescind_cb)(struct vmbus_channel *));
11021108
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−
11161109 /* The format must be the same as struct vmdata_gpa_direct */
11171110 struct vmbus_channel_packet_page_buffer {
11181111 u16 type;
@@ -1192,10 +1185,10 @@ extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, · 73 unmodified lines
11921185 extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
11931186 void *kbuffer,
11941187 u32 size,
1195− u32 *gpadl_handle);
1188+ struct vmbus_gpadl *gpadl);
11961189
11971190 extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
1198− u32 gpadl_handle);
1191+ struct vmbus_gpadl *gpadl);
11991192
12001193 void vmbus_reset_channel_cb(struct vmbus_channel *channel);
12011194