|
14 | 14 | #define has_cpuflag(f) boot_cpu_has(f)
|
15 | 15 | #endif
|
16 | 16 |
|
| 17 | +/* I/O parameters for CPUID-related helpers */ |
| 18 | +struct cpuid_leaf { |
| 19 | + u32 fn; |
| 20 | + u32 subfn; |
| 21 | + u32 eax; |
| 22 | + u32 ebx; |
| 23 | + u32 ecx; |
| 24 | + u32 edx; |
| 25 | +}; |
| 26 | + |
17 | 27 | /*
|
18 | 28 | * Since feature negotiation related variables are set early in the boot
|
19 | 29 | * process they must reside in the .data section so as not to be zeroed
|
@@ -194,47 +204,68 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr,
|
194 | 204 | return verify_exception_info(ghcb, ctxt);
|
195 | 205 | }
|
196 | 206 |
|
| 207 | +static int __sev_cpuid_hv(u32 fn, int reg_idx, u32 *reg) |
| 208 | +{ |
| 209 | + u64 val; |
| 210 | + |
| 211 | + sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, reg_idx)); |
| 212 | + VMGEXIT(); |
| 213 | + val = sev_es_rd_ghcb_msr(); |
| 214 | + if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) |
| 215 | + return -EIO; |
| 216 | + |
| 217 | + *reg = (val >> 32); |
| 218 | + |
| 219 | + return 0; |
| 220 | +} |
| 221 | + |
| 222 | +static int sev_cpuid_hv(struct cpuid_leaf *leaf) |
| 223 | +{ |
| 224 | + int ret; |
| 225 | + |
| 226 | + /* |
| 227 | + * MSR protocol does not support fetching non-zero subfunctions, but is |
| 228 | + * sufficient to handle current early-boot cases. Should that change, |
| 229 | + * make sure to report an error rather than ignoring the index and |
| 230 | + * grabbing random values. If this issue arises in the future, handling |
| 231 | + * can be added here to use GHCB-page protocol for cases that occur late |
| 232 | + * enough in boot that GHCB page is available. |
| 233 | + */ |
| 234 | + if (cpuid_function_is_indexed(leaf->fn) && leaf->subfn) |
| 235 | + return -EINVAL; |
| 236 | + |
| 237 | + ret = __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EAX, &leaf->eax); |
| 238 | + ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EBX, &leaf->ebx); |
| 239 | + ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_ECX, &leaf->ecx); |
| 240 | + ret = ret ? : __sev_cpuid_hv(leaf->fn, GHCB_CPUID_REQ_EDX, &leaf->edx); |
| 241 | + |
| 242 | + return ret; |
| 243 | +} |
| 244 | + |
197 | 245 | /*
|
198 | 246 | * Boot VC Handler - This is the first VC handler during boot, there is no GHCB
|
199 | 247 | * page yet, so it only supports the MSR based communication with the
|
200 | 248 | * hypervisor and only the CPUID exit-code.
|
201 | 249 | */
|
202 | 250 | void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
|
203 | 251 | {
|
| 252 | + unsigned int subfn = lower_bits(regs->cx, 32); |
204 | 253 | unsigned int fn = lower_bits(regs->ax, 32);
|
205 |
| - unsigned long val; |
| 254 | + struct cpuid_leaf leaf; |
206 | 255 |
|
207 | 256 | /* Only CPUID is supported via MSR protocol */
|
208 | 257 | if (exit_code != SVM_EXIT_CPUID)
|
209 | 258 | goto fail;
|
210 | 259 |
|
211 |
| - sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EAX)); |
212 |
| - VMGEXIT(); |
213 |
| - val = sev_es_rd_ghcb_msr(); |
214 |
| - if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) |
215 |
| - goto fail; |
216 |
| - regs->ax = val >> 32; |
217 |
| - |
218 |
| - sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EBX)); |
219 |
| - VMGEXIT(); |
220 |
| - val = sev_es_rd_ghcb_msr(); |
221 |
| - if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) |
222 |
| - goto fail; |
223 |
| - regs->bx = val >> 32; |
224 |
| - |
225 |
| - sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_ECX)); |
226 |
| - VMGEXIT(); |
227 |
| - val = sev_es_rd_ghcb_msr(); |
228 |
| - if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) |
| 260 | + leaf.fn = fn; |
| 261 | + leaf.subfn = subfn; |
| 262 | + if (sev_cpuid_hv(&leaf)) |
229 | 263 | goto fail;
|
230 |
| - regs->cx = val >> 32; |
231 | 264 |
|
232 |
| - sev_es_wr_ghcb_msr(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EDX)); |
233 |
| - VMGEXIT(); |
234 |
| - val = sev_es_rd_ghcb_msr(); |
235 |
| - if (GHCB_RESP_CODE(val) != GHCB_MSR_CPUID_RESP) |
236 |
| - goto fail; |
237 |
| - regs->dx = val >> 32; |
| 265 | + regs->ax = leaf.eax; |
| 266 | + regs->bx = leaf.ebx; |
| 267 | + regs->cx = leaf.ecx; |
| 268 | + regs->dx = leaf.edx; |
238 | 269 |
|
239 | 270 | /*
|
240 | 271 | * This is a VC handler and the #VC is only raised when SEV-ES is
|
|
0 commit comments