Skip to content

Commit

Permalink
x86/hyperv: Initialize GHCB page in Isolation VM
Browse files Browse the repository at this point in the history
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 <mikelley@microsoft.com>
Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
Link: https://lore.kernel.org/r/20211025122116.264793-2-ltykernel@gmail.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
  • Loading branch information
Tianyu Lan authored and Wei Liu committed Oct 28, 2021
1 parent e82f206 commit 0cc4f6d
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 7 deletions.
68 changes: 61 additions & 7 deletions arch/x86/hyperv/hv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/kexec.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/hyperv.h>
#include <linux/slab.h>
Expand All @@ -36,12 +37,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id);
void *hv_hypercall_pg;
EXPORT_SYMBOL_GPL(hv_hypercall_pg);

void __percpu **hv_ghcb_pg;

/* Storage to save the hypercall page temporarily for hibernation */
static void *hv_hypercall_pg_saved;

struct hv_vp_assist_page **hv_vp_assist_page;
EXPORT_SYMBOL_GPL(hv_vp_assist_page);

static int hyperv_init_ghcb(void)
{
u64 ghcb_gpa;
void *ghcb_va;
void **ghcb_base;

if (!hv_isolation_type_snp())
return 0;

if (!hv_ghcb_pg)
return -EINVAL;

/*
* GHCB page is allocated by paravisor. The address
* returned by MSR_AMD64_SEV_ES_GHCB is above shared
* memory boundary and map it here.
*/
rdmsrl(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa);
ghcb_va = memremap(ghcb_gpa, HV_HYP_PAGE_SIZE, MEMREMAP_WB);
if (!ghcb_va)
return -ENOMEM;

ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg);
*ghcb_base = ghcb_va;

return 0;
}

static int hv_cpu_init(unsigned int cpu)
{
union hv_vp_assist_msr_contents msr = { 0 };
Expand Down Expand Up @@ -85,7 +116,7 @@ static int hv_cpu_init(unsigned int cpu)
}
}

return 0;
return hyperv_init_ghcb();
}

static void (*hv_reenlightenment_cb)(void);
Expand Down Expand Up @@ -177,6 +208,14 @@ static int hv_cpu_die(unsigned int cpu)
{
struct hv_reenlightenment_control re_ctrl;
unsigned int new_cpu;
void **ghcb_va;

if (hv_ghcb_pg) {
ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg);
if (*ghcb_va)
memunmap(*ghcb_va);
*ghcb_va = NULL;
}

hv_common_cpu_die(cpu);

Expand Down Expand Up @@ -366,10 +405,16 @@ void __init hyperv_init(void)
goto common_free;
}

if (hv_isolation_type_snp()) {
hv_ghcb_pg = alloc_percpu(void *);
if (!hv_ghcb_pg)
goto free_vp_assist_page;
}

cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
hv_cpu_init, hv_cpu_die);
if (cpuhp < 0)
goto free_vp_assist_page;
goto free_ghcb_page;

/*
* Setup the hypercall page and enable hypercalls.
Expand All @@ -383,10 +428,8 @@ void __init hyperv_init(void)
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
__builtin_return_address(0));
if (hv_hypercall_pg == NULL) {
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
goto remove_cpuhp_state;
}
if (hv_hypercall_pg == NULL)
goto clean_guest_os_id;

rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
hypercall_msr.enable = 1;
Expand Down Expand Up @@ -456,8 +499,11 @@ void __init hyperv_init(void)
hv_query_ext_cap(0);
return;

remove_cpuhp_state:
clean_guest_os_id:
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
cpuhp_remove_state(cpuhp);
free_ghcb_page:
free_percpu(hv_ghcb_pg);
free_vp_assist_page:
kfree(hv_vp_assist_page);
hv_vp_assist_page = NULL;
Expand Down Expand Up @@ -559,3 +605,11 @@ bool hv_is_isolation_supported(void)
{
return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
}

DEFINE_STATIC_KEY_FALSE(isolation_type_snp);

bool hv_isolation_type_snp(void)
{
return static_branch_unlikely(&isolation_type_snp);
}
EXPORT_SYMBOL_GPL(hv_isolation_type_snp);
4 changes: 4 additions & 0 deletions arch/x86/include/asm/mshyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <asm/paravirt.h>
#include <asm/mshyperv.h>

DECLARE_STATIC_KEY_FALSE(isolation_type_snp);

typedef int (*hyperv_fill_flush_list_func)(
struct hv_guest_mapping_flush_list *flush,
void *data);
Expand Down Expand Up @@ -39,6 +41,8 @@ extern void *hv_hypercall_pg;

extern u64 hv_current_partition_id;

extern void __percpu **hv_ghcb_pg;

int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);
Expand Down
3 changes: 3 additions & 0 deletions arch/x86/kernel/cpu/mshyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ static void __init ms_hyperv_init_platform(void)

pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n",
ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b);

if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP)
static_branch_enable(&isolation_type_snp);
}

if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) {
Expand Down
6 changes: 6 additions & 0 deletions include/asm-generic/mshyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,18 @@ bool hv_is_hyperv_initialized(void);
bool hv_is_hibernation_supported(void);
enum hv_isolation_type hv_get_isolation_type(void);
bool hv_is_isolation_supported(void);
bool hv_isolation_type_snp(void);
void hyperv_cleanup(void);
bool hv_query_ext_cap(u64 cap_query);
#else /* CONFIG_HYPERV */
static inline bool hv_is_hyperv_initialized(void) { return false; }
static inline bool hv_is_hibernation_supported(void) { return false; }
static inline void hyperv_cleanup(void) {}
static inline bool hv_is_isolation_supported(void) { return false; }
static inline enum hv_isolation_type hv_get_isolation_type(void)
{
return HV_ISOLATION_TYPE_NONE;
}
#endif /* CONFIG_HYPERV */

#endif

0 comments on commit 0cc4f6d

Please sign in to comment.