Skip to content

Commit 0cc4f6d

Browse files
Tianyu Lanliuw
authored andcommitted
x86/hyperv: Initialize GHCB page in Isolation VM
Hyperv exposes GHCB page via SEV ES GHCB MSR for SNP guest to communicate with hypervisor. Map GHCB page for all cpus to read/write MSR register and submit hvcall request via ghcb page. Reviewed-by: Michael Kelley <[email protected]> Signed-off-by: Tianyu Lan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent e82f206 commit 0cc4f6d

File tree

4 files changed

+74
-7
lines changed

4 files changed

+74
-7
lines changed

arch/x86/hyperv/hv_init.c

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/kexec.h>
2121
#include <linux/version.h>
2222
#include <linux/vmalloc.h>
23+
#include <linux/io.h>
2324
#include <linux/mm.h>
2425
#include <linux/hyperv.h>
2526
#include <linux/slab.h>
@@ -36,12 +37,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id);
3637
void *hv_hypercall_pg;
3738
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
3839

40+
void __percpu **hv_ghcb_pg;
41+
3942
/* Storage to save the hypercall page temporarily for hibernation */
4043
static void *hv_hypercall_pg_saved;
4144

4245
struct hv_vp_assist_page **hv_vp_assist_page;
4346
EXPORT_SYMBOL_GPL(hv_vp_assist_page);
4447

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+
4576
static int hv_cpu_init(unsigned int cpu)
4677
{
4778
union hv_vp_assist_msr_contents msr = { 0 };
@@ -85,7 +116,7 @@ static int hv_cpu_init(unsigned int cpu)
85116
}
86117
}
87118

88-
return 0;
119+
return hyperv_init_ghcb();
89120
}
90121

91122
static void (*hv_reenlightenment_cb)(void);
@@ -177,6 +208,14 @@ static int hv_cpu_die(unsigned int cpu)
177208
{
178209
struct hv_reenlightenment_control re_ctrl;
179210
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+
}
180219

181220
hv_common_cpu_die(cpu);
182221

@@ -366,10 +405,16 @@ void __init hyperv_init(void)
366405
goto common_free;
367406
}
368407

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+
369414
cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
370415
hv_cpu_init, hv_cpu_die);
371416
if (cpuhp < 0)
372-
goto free_vp_assist_page;
417+
goto free_ghcb_page;
373418

374419
/*
375420
* Setup the hypercall page and enable hypercalls.
@@ -383,10 +428,8 @@ void __init hyperv_init(void)
383428
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
384429
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
385430
__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;
390433

391434
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
392435
hypercall_msr.enable = 1;
@@ -456,8 +499,11 @@ void __init hyperv_init(void)
456499
hv_query_ext_cap(0);
457500
return;
458501

459-
remove_cpuhp_state:
502+
clean_guest_os_id:
503+
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
460504
cpuhp_remove_state(cpuhp);
505+
free_ghcb_page:
506+
free_percpu(hv_ghcb_pg);
461507
free_vp_assist_page:
462508
kfree(hv_vp_assist_page);
463509
hv_vp_assist_page = NULL;
@@ -559,3 +605,11 @@ bool hv_is_isolation_supported(void)
559605
{
560606
return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
561607
}
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);

arch/x86/include/asm/mshyperv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <asm/paravirt.h>
1212
#include <asm/mshyperv.h>
1313

14+
DECLARE_STATIC_KEY_FALSE(isolation_type_snp);
15+
1416
typedef int (*hyperv_fill_flush_list_func)(
1517
struct hv_guest_mapping_flush_list *flush,
1618
void *data);
@@ -39,6 +41,8 @@ extern void *hv_hypercall_pg;
3941

4042
extern u64 hv_current_partition_id;
4143

44+
extern void __percpu **hv_ghcb_pg;
45+
4246
int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
4347
int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
4448
int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ static void __init ms_hyperv_init_platform(void)
316316

317317
pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n",
318318
ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b);
319+
320+
if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP)
321+
static_branch_enable(&isolation_type_snp);
319322
}
320323

321324
if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) {

include/asm-generic/mshyperv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,18 @@ bool hv_is_hyperv_initialized(void);
254254
bool hv_is_hibernation_supported(void);
255255
enum hv_isolation_type hv_get_isolation_type(void);
256256
bool hv_is_isolation_supported(void);
257+
bool hv_isolation_type_snp(void);
257258
void hyperv_cleanup(void);
258259
bool hv_query_ext_cap(u64 cap_query);
259260
#else /* CONFIG_HYPERV */
260261
static inline bool hv_is_hyperv_initialized(void) { return false; }
261262
static inline bool hv_is_hibernation_supported(void) { return false; }
262263
static inline void hyperv_cleanup(void) {}
264+
static inline bool hv_is_isolation_supported(void) { return false; }
265+
static inline enum hv_isolation_type hv_get_isolation_type(void)
266+
{
267+
return HV_ISOLATION_TYPE_NONE;
268+
}
263269
#endif /* CONFIG_HYPERV */
264270

265271
#endif

0 commit comments

Comments
 (0)