diff options
Diffstat (limited to 'arch/x86/hyperv/hv_init.c')
| -rw-r--r-- | arch/x86/hyperv/hv_init.c | 82 | 
1 files changed, 61 insertions, 21 deletions
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 708a2712a516..24f4a06ac46a 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -36,12 +36,42 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id);  void *hv_hypercall_pg;  EXPORT_SYMBOL_GPL(hv_hypercall_pg); +union hv_ghcb __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 }; @@ -85,7 +115,7 @@ static int hv_cpu_init(unsigned int cpu)  		}  	} -	return 0; +	return hyperv_init_ghcb();  }  static void (*hv_reenlightenment_cb)(void); @@ -139,7 +169,6 @@ void set_hv_tscchange_cb(void (*cb)(void))  	struct hv_reenlightenment_control re_ctrl = {  		.vector = HYPERV_REENLIGHTENMENT_VECTOR,  		.enabled = 1, -		.target_vp = hv_vp_index[smp_processor_id()]  	};  	struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1}; @@ -153,8 +182,12 @@ void set_hv_tscchange_cb(void (*cb)(void))  	/* Make sure callback is registered before we write to MSRs */  	wmb(); +	re_ctrl.target_vp = hv_vp_index[get_cpu()]; +  	wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));  	wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl)); + +	put_cpu();  }  EXPORT_SYMBOL_GPL(set_hv_tscchange_cb); @@ -177,6 +210,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); @@ -366,10 +407,16 @@ void __init hyperv_init(void)  		goto common_free;  	} +	if (hv_isolation_type_snp()) { +		hv_ghcb_pg = alloc_percpu(union hv_ghcb *); +		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. @@ -379,14 +426,15 @@ void __init hyperv_init(void)  	guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);  	wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); +	/* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ +	hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id); +  	hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START,  			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; @@ -456,8 +504,12 @@ 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); +	hv_ghcb_msr_write(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; @@ -476,6 +528,7 @@ void hyperv_cleanup(void)  	/* Reset our OS id */  	wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); +	hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0);  	/*  	 * Reset hypercall page reference before reset the page, @@ -546,16 +599,3 @@ bool hv_is_hyperv_initialized(void)  	return hypercall_msr.enable;  }  EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized); - -enum hv_isolation_type hv_get_isolation_type(void) -{ -	if (!(ms_hyperv.priv_high & HV_ISOLATION)) -		return HV_ISOLATION_TYPE_NONE; -	return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b); -} -EXPORT_SYMBOL_GPL(hv_get_isolation_type); - -bool hv_is_isolation_supported(void) -{ -	return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; -}  |