Skip to content

Commit 49d6a3c

Browse files
Tianyu Lanliuw
authored andcommitted
x86/Hyper-V: Add SEV negotiate protocol support in Isolation VM
Hyper-V Isolation VM current code uses sev_es_ghcb_hv_call() to read/write MSR via GHCB page and depends on the sev code. This may cause regression when sev code changes interface design. The latest SEV-ES code requires to negotiate GHCB version before reading/writing MSR via GHCB page and sev_es_ghcb_hv_call() doesn't work for Hyper-V Isolation VM. Add Hyper-V ghcb related implementation to decouple SEV and Hyper-V code. Negotiate GHCB version in the hyperv_init() and use the version to communicate with Hyper-V in the ghcb hv call function. Fixes: 2ea29c5 ("x86/sev: Save the negotiated GHCB version") Signed-off-by: Tianyu Lan <[email protected]> Reviewed-by: Michael Kelley <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent 656c5ba commit 49d6a3c

File tree

3 files changed

+88
-6
lines changed

3 files changed

+88
-6
lines changed

arch/x86/hyperv/hv_init.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/io.h>
1414
#include <asm/apic.h>
1515
#include <asm/desc.h>
16+
#include <asm/sev.h>
1617
#include <asm/hypervisor.h>
1718
#include <asm/hyperv-tlfs.h>
1819
#include <asm/mshyperv.h>
@@ -405,6 +406,11 @@ void __init hyperv_init(void)
405406
}
406407

407408
if (hv_isolation_type_snp()) {
409+
/* Negotiate GHCB Version. */
410+
if (!hv_ghcb_negotiate_protocol())
411+
hv_ghcb_terminate(SEV_TERM_SET_GEN,
412+
GHCB_SEV_ES_PROT_UNSUPPORTED);
413+
408414
hv_ghcb_pg = alloc_percpu(union hv_ghcb *);
409415
if (!hv_ghcb_pg)
410416
goto free_vp_assist_page;

arch/x86/hyperv/ivm.c

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ union hv_ghcb {
5353
} hypercall;
5454
} __packed __aligned(HV_HYP_PAGE_SIZE);
5555

56+
static u16 hv_ghcb_version __ro_after_init;
57+
5658
u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size)
5759
{
5860
union hv_ghcb *hv_ghcb;
@@ -96,12 +98,85 @@ u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size)
9698
return status;
9799
}
98100

101+
static inline u64 rd_ghcb_msr(void)
102+
{
103+
return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
104+
}
105+
106+
static inline void wr_ghcb_msr(u64 val)
107+
{
108+
native_wrmsrl(MSR_AMD64_SEV_ES_GHCB, val);
109+
}
110+
111+
static enum es_result hv_ghcb_hv_call(struct ghcb *ghcb, u64 exit_code,
112+
u64 exit_info_1, u64 exit_info_2)
113+
{
114+
/* Fill in protocol and format specifiers */
115+
ghcb->protocol_version = hv_ghcb_version;
116+
ghcb->ghcb_usage = GHCB_DEFAULT_USAGE;
117+
118+
ghcb_set_sw_exit_code(ghcb, exit_code);
119+
ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
120+
ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
121+
122+
VMGEXIT();
123+
124+
if (ghcb->save.sw_exit_info_1 & GENMASK_ULL(31, 0))
125+
return ES_VMM_ERROR;
126+
else
127+
return ES_OK;
128+
}
129+
130+
void hv_ghcb_terminate(unsigned int set, unsigned int reason)
131+
{
132+
u64 val = GHCB_MSR_TERM_REQ;
133+
134+
/* Tell the hypervisor what went wrong. */
135+
val |= GHCB_SEV_TERM_REASON(set, reason);
136+
137+
/* Request Guest Termination from Hypvervisor */
138+
wr_ghcb_msr(val);
139+
VMGEXIT();
140+
141+
while (true)
142+
asm volatile("hlt\n" : : : "memory");
143+
}
144+
145+
bool hv_ghcb_negotiate_protocol(void)
146+
{
147+
u64 ghcb_gpa;
148+
u64 val;
149+
150+
/* Save ghcb page gpa. */
151+
ghcb_gpa = rd_ghcb_msr();
152+
153+
/* Do the GHCB protocol version negotiation */
154+
wr_ghcb_msr(GHCB_MSR_SEV_INFO_REQ);
155+
VMGEXIT();
156+
val = rd_ghcb_msr();
157+
158+
if (GHCB_MSR_INFO(val) != GHCB_MSR_SEV_INFO_RESP)
159+
return false;
160+
161+
if (GHCB_MSR_PROTO_MAX(val) < GHCB_PROTOCOL_MIN ||
162+
GHCB_MSR_PROTO_MIN(val) > GHCB_PROTOCOL_MAX)
163+
return false;
164+
165+
hv_ghcb_version = min_t(size_t, GHCB_MSR_PROTO_MAX(val),
166+
GHCB_PROTOCOL_MAX);
167+
168+
/* Write ghcb page back after negotiating protocol. */
169+
wr_ghcb_msr(ghcb_gpa);
170+
VMGEXIT();
171+
172+
return true;
173+
}
174+
99175
void hv_ghcb_msr_write(u64 msr, u64 value)
100176
{
101177
union hv_ghcb *hv_ghcb;
102178
void **ghcb_base;
103179
unsigned long flags;
104-
struct es_em_ctxt ctxt;
105180

106181
if (!hv_ghcb_pg)
107182
return;
@@ -120,8 +195,7 @@ void hv_ghcb_msr_write(u64 msr, u64 value)
120195
ghcb_set_rax(&hv_ghcb->ghcb, lower_32_bits(value));
121196
ghcb_set_rdx(&hv_ghcb->ghcb, upper_32_bits(value));
122197

123-
if (sev_es_ghcb_hv_call(&hv_ghcb->ghcb, false, &ctxt,
124-
SVM_EXIT_MSR, 1, 0))
198+
if (hv_ghcb_hv_call(&hv_ghcb->ghcb, SVM_EXIT_MSR, 1, 0))
125199
pr_warn("Fail to write msr via ghcb %llx.\n", msr);
126200

127201
local_irq_restore(flags);
@@ -133,7 +207,6 @@ void hv_ghcb_msr_read(u64 msr, u64 *value)
133207
union hv_ghcb *hv_ghcb;
134208
void **ghcb_base;
135209
unsigned long flags;
136-
struct es_em_ctxt ctxt;
137210

138211
/* Check size of union hv_ghcb here. */
139212
BUILD_BUG_ON(sizeof(union hv_ghcb) != HV_HYP_PAGE_SIZE);
@@ -152,8 +225,7 @@ void hv_ghcb_msr_read(u64 msr, u64 *value)
152225
}
153226

154227
ghcb_set_rcx(&hv_ghcb->ghcb, msr);
155-
if (sev_es_ghcb_hv_call(&hv_ghcb->ghcb, false, &ctxt,
156-
SVM_EXIT_MSR, 0, 0))
228+
if (hv_ghcb_hv_call(&hv_ghcb->ghcb, SVM_EXIT_MSR, 0, 0))
157229
pr_warn("Fail to read msr via ghcb %llx.\n", msr);
158230
else
159231
*value = (u64)lower_32_bits(hv_ghcb->ghcb.save.rax)

arch/x86/include/asm/mshyperv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,13 @@ int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible);
179179
#ifdef CONFIG_AMD_MEM_ENCRYPT
180180
void hv_ghcb_msr_write(u64 msr, u64 value);
181181
void hv_ghcb_msr_read(u64 msr, u64 *value);
182+
bool hv_ghcb_negotiate_protocol(void);
183+
void hv_ghcb_terminate(unsigned int set, unsigned int reason);
182184
#else
183185
static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
184186
static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
187+
static inline bool hv_ghcb_negotiate_protocol(void) { return false; }
188+
static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {}
185189
#endif
186190

187191
extern bool hv_isolation_type_snp(void);

0 commit comments

Comments
 (0)