20
20
#include <linux/kexec.h>
21
21
#include <linux/version.h>
22
22
#include <linux/vmalloc.h>
23
+ #include <linux/io.h>
23
24
#include <linux/mm.h>
24
25
#include <linux/hyperv.h>
25
26
#include <linux/slab.h>
@@ -36,12 +37,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id);
36
37
void * hv_hypercall_pg ;
37
38
EXPORT_SYMBOL_GPL (hv_hypercall_pg );
38
39
40
+ void __percpu * * hv_ghcb_pg ;
41
+
39
42
/* Storage to save the hypercall page temporarily for hibernation */
40
43
static void * hv_hypercall_pg_saved ;
41
44
42
45
struct hv_vp_assist_page * * hv_vp_assist_page ;
43
46
EXPORT_SYMBOL_GPL (hv_vp_assist_page );
44
47
48
+ static int hyperv_init_ghcb (void )
49
+ {
50
+ u64 ghcb_gpa ;
51
+ void * ghcb_va ;
52
+ void * * ghcb_base ;
53
+
54
+ if (!hv_isolation_type_snp ())
55
+ return 0 ;
56
+
57
+ if (!hv_ghcb_pg )
58
+ return - EINVAL ;
59
+
60
+ /*
61
+ * GHCB page is allocated by paravisor. The address
62
+ * returned by MSR_AMD64_SEV_ES_GHCB is above shared
63
+ * memory boundary and map it here.
64
+ */
65
+ rdmsrl (MSR_AMD64_SEV_ES_GHCB , ghcb_gpa );
66
+ ghcb_va = memremap (ghcb_gpa , HV_HYP_PAGE_SIZE , MEMREMAP_WB );
67
+ if (!ghcb_va )
68
+ return - ENOMEM ;
69
+
70
+ ghcb_base = (void * * )this_cpu_ptr (hv_ghcb_pg );
71
+ * ghcb_base = ghcb_va ;
72
+
73
+ return 0 ;
74
+ }
75
+
45
76
static int hv_cpu_init (unsigned int cpu )
46
77
{
47
78
union hv_vp_assist_msr_contents msr = { 0 };
@@ -85,7 +116,7 @@ static int hv_cpu_init(unsigned int cpu)
85
116
}
86
117
}
87
118
88
- return 0 ;
119
+ return hyperv_init_ghcb () ;
89
120
}
90
121
91
122
static void (* hv_reenlightenment_cb )(void );
@@ -177,6 +208,14 @@ static int hv_cpu_die(unsigned int cpu)
177
208
{
178
209
struct hv_reenlightenment_control re_ctrl ;
179
210
unsigned int new_cpu ;
211
+ void * * ghcb_va ;
212
+
213
+ if (hv_ghcb_pg ) {
214
+ ghcb_va = (void * * )this_cpu_ptr (hv_ghcb_pg );
215
+ if (* ghcb_va )
216
+ memunmap (* ghcb_va );
217
+ * ghcb_va = NULL ;
218
+ }
180
219
181
220
hv_common_cpu_die (cpu );
182
221
@@ -366,10 +405,16 @@ void __init hyperv_init(void)
366
405
goto common_free ;
367
406
}
368
407
408
+ if (hv_isolation_type_snp ()) {
409
+ hv_ghcb_pg = alloc_percpu (void * );
410
+ if (!hv_ghcb_pg )
411
+ goto free_vp_assist_page ;
412
+ }
413
+
369
414
cpuhp = cpuhp_setup_state (CPUHP_AP_ONLINE_DYN , "x86/hyperv_init:online" ,
370
415
hv_cpu_init , hv_cpu_die );
371
416
if (cpuhp < 0 )
372
- goto free_vp_assist_page ;
417
+ goto free_ghcb_page ;
373
418
374
419
/*
375
420
* Setup the hypercall page and enable hypercalls.
@@ -383,10 +428,8 @@ void __init hyperv_init(void)
383
428
VMALLOC_END , GFP_KERNEL , PAGE_KERNEL_ROX ,
384
429
VM_FLUSH_RESET_PERMS , NUMA_NO_NODE ,
385
430
__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
- }
431
+ if (hv_hypercall_pg == NULL )
432
+ goto clean_guest_os_id ;
390
433
391
434
rdmsrl (HV_X64_MSR_HYPERCALL , hypercall_msr .as_uint64 );
392
435
hypercall_msr .enable = 1 ;
@@ -456,8 +499,11 @@ void __init hyperv_init(void)
456
499
hv_query_ext_cap (0 );
457
500
return ;
458
501
459
- remove_cpuhp_state :
502
+ clean_guest_os_id :
503
+ wrmsrl (HV_X64_MSR_GUEST_OS_ID , 0 );
460
504
cpuhp_remove_state (cpuhp );
505
+ free_ghcb_page :
506
+ free_percpu (hv_ghcb_pg );
461
507
free_vp_assist_page :
462
508
kfree (hv_vp_assist_page );
463
509
hv_vp_assist_page = NULL ;
@@ -559,3 +605,11 @@ bool hv_is_isolation_supported(void)
559
605
{
560
606
return hv_get_isolation_type () != HV_ISOLATION_TYPE_NONE ;
561
607
}
608
+
609
+ DEFINE_STATIC_KEY_FALSE (isolation_type_snp );
610
+
611
+ bool hv_isolation_type_snp (void )
612
+ {
613
+ return static_branch_unlikely (& isolation_type_snp );
614
+ }
615
+ EXPORT_SYMBOL_GPL (hv_isolation_type_snp );
0 commit comments