Commit b9b4fe3a authored by Dexuan Cui's avatar Dexuan Cui Committed by Wei Liu

x86/hyperv: Use TDX GHCI to access some MSRs in a TDX VM with the paravisor

When the paravisor is present, a SNP VM must use GHCB to access some
special MSRs, including HV_X64_MSR_GUEST_OS_ID and some SynIC MSRs.

Similarly, when the paravisor is present, a TDX VM must use TDX GHCI
to access the same MSRs.

Implement hv_tdx_msr_write() and hv_tdx_msr_read(), and use the helper
functions hv_ivm_msr_read() and hv_ivm_msr_write() to access the MSRs
in a unified way for SNP/TDX VMs with the paravisor.

Do not export hv_tdx_msr_write() and hv_tdx_msr_read(), because we never
really used hv_ghcb_msr_write() and hv_ghcb_msr_read() in any module.

Update arch/x86/include/asm/mshyperv.h so that the kernel can still build
if CONFIG_AMD_MEM_ENCRYPT or CONFIG_INTEL_TDX_GUEST is not set, or
neither is set.
Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
Reviewed-by: default avatarTianyu Lan <tiala@microsoft.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Signed-off-by: default avatarWei Liu <wei.liu@kernel.org>
Link: https://lore.kernel.org/r/20230824080712.30327-9-decui@microsoft.com
parent 23378295
...@@ -500,8 +500,8 @@ void __init hyperv_init(void) ...@@ -500,8 +500,8 @@ void __init hyperv_init(void)
guest_id = hv_generate_guest_id(LINUX_VERSION_CODE); guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
/* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ /* With the paravisor, the VM must also write the ID via GHCB/GHCI */
hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id); hv_ivm_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id);
/* A TDX VM with no paravisor only uses TDX GHCI rather than hv_hypercall_pg */ /* A TDX VM with no paravisor only uses TDX GHCI rather than hv_hypercall_pg */
if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present) if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present)
...@@ -590,7 +590,7 @@ void __init hyperv_init(void) ...@@ -590,7 +590,7 @@ void __init hyperv_init(void)
clean_guest_os_id: clean_guest_os_id:
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); hv_ivm_msr_write(HV_X64_MSR_GUEST_OS_ID, 0);
cpuhp_remove_state(cpuhp); cpuhp_remove_state(cpuhp);
free_ghcb_page: free_ghcb_page:
free_percpu(hv_ghcb_pg); free_percpu(hv_ghcb_pg);
...@@ -611,7 +611,7 @@ void hyperv_cleanup(void) ...@@ -611,7 +611,7 @@ void hyperv_cleanup(void)
/* Reset our OS id */ /* Reset our OS id */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); hv_ivm_msr_write(HV_X64_MSR_GUEST_OS_ID, 0);
/* /*
* Reset hypercall page reference before reset the page, * Reset hypercall page reference before reset the page,
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/realmode.h> #include <asm/realmode.h>
#include <asm/e820/api.h> #include <asm/e820/api.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <uapi/asm/vmx.h>
#ifdef CONFIG_AMD_MEM_ENCRYPT #ifdef CONFIG_AMD_MEM_ENCRYPT
...@@ -186,7 +187,7 @@ bool hv_ghcb_negotiate_protocol(void) ...@@ -186,7 +187,7 @@ bool hv_ghcb_negotiate_protocol(void)
return true; return true;
} }
void hv_ghcb_msr_write(u64 msr, u64 value) static void hv_ghcb_msr_write(u64 msr, u64 value)
{ {
union hv_ghcb *hv_ghcb; union hv_ghcb *hv_ghcb;
void **ghcb_base; void **ghcb_base;
...@@ -214,9 +215,8 @@ void hv_ghcb_msr_write(u64 msr, u64 value) ...@@ -214,9 +215,8 @@ void hv_ghcb_msr_write(u64 msr, u64 value)
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL_GPL(hv_ghcb_msr_write);
void hv_ghcb_msr_read(u64 msr, u64 *value) static void hv_ghcb_msr_read(u64 msr, u64 *value)
{ {
union hv_ghcb *hv_ghcb; union hv_ghcb *hv_ghcb;
void **ghcb_base; void **ghcb_base;
...@@ -246,10 +246,71 @@ void hv_ghcb_msr_read(u64 msr, u64 *value) ...@@ -246,10 +246,71 @@ void hv_ghcb_msr_read(u64 msr, u64 *value)
| ((u64)lower_32_bits(hv_ghcb->ghcb.save.rdx) << 32); | ((u64)lower_32_bits(hv_ghcb->ghcb.save.rdx) << 32);
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL_GPL(hv_ghcb_msr_read);
#else
static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
#endif /* CONFIG_AMD_MEM_ENCRYPT */ #endif /* CONFIG_AMD_MEM_ENCRYPT */
#ifdef CONFIG_INTEL_TDX_GUEST
static void hv_tdx_msr_write(u64 msr, u64 val)
{
struct tdx_hypercall_args args = {
.r10 = TDX_HYPERCALL_STANDARD,
.r11 = EXIT_REASON_MSR_WRITE,
.r12 = msr,
.r13 = val,
};
u64 ret = __tdx_hypercall(&args);
WARN_ONCE(ret, "Failed to emulate MSR write: %lld\n", ret);
}
static void hv_tdx_msr_read(u64 msr, u64 *val)
{
struct tdx_hypercall_args args = {
.r10 = TDX_HYPERCALL_STANDARD,
.r11 = EXIT_REASON_MSR_READ,
.r12 = msr,
};
u64 ret = __tdx_hypercall_ret(&args);
if (WARN_ONCE(ret, "Failed to emulate MSR read: %lld\n", ret))
*val = 0;
else
*val = args.r11;
}
#else
static inline void hv_tdx_msr_write(u64 msr, u64 value) {}
static inline void hv_tdx_msr_read(u64 msr, u64 *value) {}
#endif /* CONFIG_INTEL_TDX_GUEST */
#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
void hv_ivm_msr_write(u64 msr, u64 value)
{
if (!ms_hyperv.paravisor_present)
return;
if (hv_isolation_type_tdx())
hv_tdx_msr_write(msr, value);
else if (hv_isolation_type_snp())
hv_ghcb_msr_write(msr, value);
}
void hv_ivm_msr_read(u64 msr, u64 *value)
{
if (!ms_hyperv.paravisor_present)
return;
if (hv_isolation_type_tdx())
hv_tdx_msr_read(msr, value);
else if (hv_isolation_type_snp())
hv_ghcb_msr_read(msr, value);
}
#endif
#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST) #if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
/* /*
* hv_mark_gpa_visibility - Set pages visible to host via hvcall. * hv_mark_gpa_visibility - Set pages visible to host via hvcall.
......
...@@ -275,14 +275,10 @@ int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, ...@@ -275,14 +275,10 @@ int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector,
int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
#ifdef CONFIG_AMD_MEM_ENCRYPT #ifdef CONFIG_AMD_MEM_ENCRYPT
void hv_ghcb_msr_write(u64 msr, u64 value);
void hv_ghcb_msr_read(u64 msr, u64 *value);
bool hv_ghcb_negotiate_protocol(void); bool hv_ghcb_negotiate_protocol(void);
void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason); void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason);
int hv_snp_boot_ap(int cpu, unsigned long start_ip); int hv_snp_boot_ap(int cpu, unsigned long start_ip);
#else #else
static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
static inline bool hv_ghcb_negotiate_protocol(void) { return false; } static inline bool hv_ghcb_negotiate_protocol(void) { return false; }
static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {} static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {}
static inline int hv_snp_boot_ap(int cpu, unsigned long start_ip) { return 0; } static inline int hv_snp_boot_ap(int cpu, unsigned long start_ip) { return 0; }
...@@ -292,8 +288,12 @@ extern bool hv_isolation_type_snp(void); ...@@ -292,8 +288,12 @@ extern bool hv_isolation_type_snp(void);
#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST) #if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
void hv_vtom_init(void); void hv_vtom_init(void);
void hv_ivm_msr_write(u64 msr, u64 value);
void hv_ivm_msr_read(u64 msr, u64 *value);
#else #else
static inline void hv_vtom_init(void) {} static inline void hv_vtom_init(void) {}
static inline void hv_ivm_msr_write(u64 msr, u64 value) {}
static inline void hv_ivm_msr_read(u64 msr, u64 *value) {}
#endif #endif
static inline bool hv_is_synic_reg(unsigned int reg) static inline bool hv_is_synic_reg(unsigned int reg)
......
...@@ -70,8 +70,8 @@ u64 hv_get_non_nested_register(unsigned int reg) ...@@ -70,8 +70,8 @@ u64 hv_get_non_nested_register(unsigned int reg)
{ {
u64 value; u64 value;
if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present)
hv_ghcb_msr_read(reg, &value); hv_ivm_msr_read(reg, &value);
else else
rdmsrl(reg, value); rdmsrl(reg, value);
return value; return value;
...@@ -80,8 +80,8 @@ EXPORT_SYMBOL_GPL(hv_get_non_nested_register); ...@@ -80,8 +80,8 @@ EXPORT_SYMBOL_GPL(hv_get_non_nested_register);
void hv_set_non_nested_register(unsigned int reg, u64 value) void hv_set_non_nested_register(unsigned int reg, u64 value)
{ {
if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) { if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present) {
hv_ghcb_msr_write(reg, value); hv_ivm_msr_write(reg, value);
/* Write proxy bit via wrmsl instruction */ /* Write proxy bit via wrmsl instruction */
if (hv_is_sint_reg(reg)) if (hv_is_sint_reg(reg))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment