Skip to content

Commit b88c021

Browse files
committed
drivers: hv: Support for SNP Secure AVIC
2 parents ec12dfc + 4d255b3 commit b88c021

16 files changed

Lines changed: 769 additions & 194 deletions

File tree

arch/x86/hyperv/hv_apic.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/clockchips.h>
2626
#include <linux/slab.h>
2727
#include <linux/cpuhotplug.h>
28+
#include <linux/cc_platform.h>
2829
#include <asm/hypervisor.h>
2930
#include <asm/mshyperv.h>
3031
#include <asm/apic.h>
@@ -53,6 +54,11 @@ static void hv_apic_icr_write(u32 low, u32 id)
5354
wrmsrq(HV_X64_MSR_ICR, reg_val);
5455
}
5556

57+
void hv_enable_coco_interrupt(unsigned int cpu, unsigned int vector, bool set)
58+
{
59+
apic_update_vector(cpu, vector, set);
60+
}
61+
5662
static u32 hv_apic_read(u32 reg)
5763
{
5864
u32 reg_val, hi;
@@ -293,6 +299,9 @@ static void hv_send_ipi_self(int vector)
293299

294300
void __init hv_apic_init(void)
295301
{
302+
if (cc_platform_has(CC_ATTR_SNP_SECURE_AVIC))
303+
return;
304+
296305
if (ms_hyperv.hints & HV_X64_CLUSTER_IPI_RECOMMENDED) {
297306
pr_info("Hyper-V: Using IPI hypercalls\n");
298307
/*

arch/x86/hyperv/hv_init.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static inline void hv_set_hypercall_pg(void *ptr)
7676
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
7777
#endif
7878

79+
void *hv_vp_early_input_arg;
7980
union hv_ghcb * __percpu *hv_ghcb_pg;
8081

8182
/* Storage to save the hypercall page temporarily for hibernation */
@@ -120,6 +121,10 @@ static int hv_cpu_init(unsigned int cpu)
120121
if (ret)
121122
return ret;
122123

124+
/* Allow Hyper-V stimer vector to be injected from Hypervisor. */
125+
if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE)
126+
apic_update_vector(cpu, HYPERV_STIMER0_VECTOR, true);
127+
123128
return hyperv_init_ghcb();
124129
}
125130

@@ -227,6 +232,9 @@ static int hv_cpu_die(unsigned int cpu)
227232
*ghcb_va = NULL;
228233
}
229234

235+
if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE)
236+
apic_update_vector(cpu, HYPERV_STIMER0_VECTOR, false);
237+
230238
hv_common_cpu_die(cpu);
231239

232240
if (hv_reenlightenment_cb == NULL)
@@ -375,13 +383,32 @@ void __init hyperv_init(void)
375383
u64 guest_id;
376384
union hv_x64_msr_hypercall_contents hypercall_msr;
377385
int cpuhp;
386+
int ret;
378387

379388
if (x86_hyper_type != X86_HYPER_MS_HYPERV)
380389
return;
381390

382391
if (hv_common_init())
383392
return;
384393

394+
if (cc_platform_has(CC_ATTR_SNP_SECURE_AVIC)) {
395+
hv_vp_early_input_arg = (void *)__get_free_pages(
396+
GFP_KERNEL | __GFP_ZERO,
397+
get_order(num_possible_cpus() * PAGE_SIZE));
398+
if (hv_vp_early_input_arg) {
399+
ret = set_memory_decrypted((u64)hv_vp_early_input_arg,
400+
num_possible_cpus());
401+
if (ret) {
402+
free_pages((unsigned long)hv_vp_early_input_arg,
403+
get_order(num_possible_cpus() * PAGE_SIZE));
404+
hv_vp_early_input_arg = NULL;
405+
goto common_free;
406+
}
407+
} else {
408+
goto common_free;
409+
}
410+
}
411+
385412
if (ms_hyperv.paravisor_present && hv_isolation_type_snp()) {
386413
/* Negotiate GHCB Version. */
387414
if (!hv_ghcb_negotiate_protocol())
@@ -519,6 +546,16 @@ void __init hyperv_init(void)
519546
free_vp_assist_page:
520547
kfree(hv_vp_assist_page);
521548
hv_vp_assist_page = NULL;
549+
free_vp_early_input_arg:
550+
if (hv_vp_early_input_arg) {
551+
set_memory_encrypted((u64)hv_vp_early_input_arg,
552+
num_possible_cpus());
553+
free_pages((unsigned long)hv_vp_early_input_arg,
554+
get_order(num_possible_cpus() * PAGE_SIZE));
555+
hv_vp_early_input_arg = NULL;
556+
}
557+
common_free:
558+
hv_common_free();
522559
}
523560

524561
/*

arch/x86/hyperv/ivm.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,45 @@ static void snp_cleanup_vmsa(struct sev_es_save_area *vmsa)
291291
free_page((unsigned long)vmsa);
292292
}
293293

294+
enum es_result hv_set_savic_backing_page(u64 gfn)
295+
{
296+
u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_SET_VP_REGISTERS;
297+
struct hv_set_vp_registers_input *input =
298+
(struct hv_set_vp_registers_input *)
299+
((u8 *)hv_vp_early_input_arg + smp_processor_id() * PAGE_SIZE);
300+
union hv_x64_register_sev_gpa_page value;
301+
unsigned long flags;
302+
int retry = 5;
303+
u64 ret;
304+
305+
local_irq_save(flags);
306+
307+
value.enabled = 1;
308+
value.reserved = 0;
309+
value.pagenumber = gfn;
310+
311+
memset(input, 0, struct_size(input, element, 1));
312+
input->header.partitionid = HV_PARTITION_ID_SELF;
313+
input->header.vpindex = HV_VP_INDEX_SELF;
314+
input->header.inputvtl = ms_hyperv.vtl;
315+
input->element[0].name = HV_X64_REGISTER_SEV_AVIC_GPA;
316+
input->element[0].value.reg64 = value.u64;
317+
318+
do {
319+
ret = hv_do_hypercall(control, input, NULL);
320+
} while (ret == HV_STATUS_TIME_OUT && retry--);
321+
322+
if (!hv_result_success(ret))
323+
pr_err("Failed to set secure AVIC backing page %llx.\n", ret);
324+
325+
local_irq_restore(flags);
326+
327+
if (hv_result_success(ret))
328+
return ES_OK;
329+
else
330+
return ES_VMM_ERROR;
331+
}
332+
294333
int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
295334
{
296335
struct sev_es_save_area *vmsa = (struct sev_es_save_area *)

arch/x86/include/asm/apic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,12 @@ static inline u64 native_x2apic_icr_read(void)
241241
return val;
242242
}
243243

244+
#if defined(CONFIG_AMD_SECURE_AVIC)
245+
extern void x2apic_savic_init_backing_page(void *backing_page);
246+
#else
247+
static inline void x2apic_savic_init_backing_page(void *backing_page) {}
248+
#endif
249+
244250
extern int x2apic_mode;
245251
extern int x2apic_phys;
246252
extern void __init x2apic_set_max_apicid(u32 apicid);

arch/x86/include/asm/mshyperv.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern u64 hv_std_hypercall(u64 control, u64 param1, u64 param2);
4444

4545
#if IS_ENABLED(CONFIG_HYPERV)
4646
extern void *hv_hypercall_pg;
47+
extern void *hv_vp_early_input_arg;
4748

4849
extern union hv_ghcb * __percpu *hv_ghcb_pg;
4950

@@ -197,6 +198,7 @@ int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
197198
bool hv_ghcb_negotiate_protocol(void);
198199
void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason);
199200
int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu);
201+
enum es_result hv_set_savic_backing_page(u64 gfn);
200202
#else
201203
static inline bool hv_ghcb_negotiate_protocol(void) { return false; }
202204
static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {}
@@ -300,6 +302,20 @@ static inline void hv_vtl_idle(void)
300302
native_safe_halt();
301303
}
302304

305+
/*
306+
* Registers are only accessible via HVCALL_GET_VP_REGISTERS hvcall and
307+
* there is not associated MSR address.
308+
*/
309+
#ifndef HV_X64_REGISTER_VSM_VP_STATUS
310+
#define HV_X64_REGISTER_VSM_VP_STATUS 0x000D0003
311+
#endif
312+
#ifndef HV_X64_VTL_MASK
313+
#define HV_X64_VTL_MASK GENMASK(3, 0)
314+
#endif
315+
#ifndef HV_X64_REGISTER_SEV_AVIC_GPA
316+
#define HV_X64_REGISTER_SEV_AVIC_GPA 0x00090043
317+
#endif
318+
303319
#ifdef CONFIG_HYPERV_VTL_MODE
304320
void __init hv_vtl_init_platform(void);
305321
int __init hv_vtl_early_init(void);

arch/x86/include/asm/sev.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@ struct rmp_state {
141141
u32 asid;
142142
} __packed;
143143

144-
#define RMPADJUST_VMSA_PAGE_BIT BIT(16)
144+
/* Target VMPL takes the first byte */
145+
#define RMPADJUST_ENABLE_READ BIT(8)
146+
#define RMPADJUST_ENABLE_WRITE BIT(9)
147+
#define RMPADJUST_USER_EXECUTE BIT(10)
148+
#define RMPADJUST_KERNEL_EXECUTE BIT(11)
149+
#define RMPADJUST_VMSA_PAGE_BIT BIT(16)
145150

146151
/* SNP Guest message request */
147152
struct snp_req_data {

arch/x86/include/asm/svm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
190190
#define V_GIF_SHIFT 9
191191
#define V_GIF_MASK (1 << V_GIF_SHIFT)
192192

193+
#define V_INT_SHADOW_SHIFT 10
194+
#define V_INT_SHADOW_MASK (1 << V_INT_SHADOW_SHIFT)
195+
193196
#define V_NMI_PENDING_SHIFT 11
194197
#define V_NMI_PENDING_MASK (1 << V_NMI_PENDING_SHIFT)
195198

@@ -202,6 +205,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
202205
#define V_IGN_TPR_SHIFT 20
203206
#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
204207

208+
#define V_GUEST_BUSY_SHIFT 63
209+
#define V_GUEST_BUSY_MASK (1ULL << V_GUEST_BUSY_SHIFT)
210+
205211
#define V_IRQ_INJECTION_BITS_MASK (V_IRQ_MASK | V_INTR_PRIO_MASK | V_IGN_TPR_MASK)
206212

207213
#define V_INTR_MASKING_SHIFT 24

arch/x86/kernel/apic/x2apic_savic.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <asm/apic.h>
1616
#include <asm/sev.h>
17+
#include <asm/mshyperv.h>
1718

1819
#include "local.h"
1920

@@ -330,6 +331,18 @@ static void savic_eoi(void)
330331
}
331332
}
332333

334+
void x2apic_savic_init_backing_page(void *ap)
335+
{
336+
u32 apic_id;
337+
338+
/*
339+
* Before Secure AVIC is enabled, APIC msr reads are intercepted.
340+
* APIC_ID msr read returns the value from the Hypervisor.
341+
*/
342+
apic_id = native_apic_msr_read(APIC_ID);
343+
apic_set_reg(ap, APIC_ID, apic_id);
344+
}
345+
333346
static void savic_teardown(void)
334347
{
335348
/* Disable Secure AVIC */
@@ -342,15 +355,16 @@ static void savic_setup(void)
342355
void *ap = this_cpu_ptr(savic_page);
343356
enum es_result res;
344357
unsigned long gpa;
358+
unsigned long gfn;
345359

346-
/*
347-
* Before Secure AVIC is enabled, APIC MSR reads are intercepted.
348-
* APIC_ID MSR read returns the value from the hypervisor.
349-
*/
350-
apic_set_reg(ap, APIC_ID, native_apic_msr_read(APIC_ID));
360+
if (!cc_platform_has(CC_ATTR_SNP_SECURE_AVIC))
361+
return;
351362

363+
x2apic_savic_init_backing_page(ap);
352364
gpa = __pa(ap);
353365

366+
gfn = gpa >> PAGE_SHIFT;
367+
354368
/*
355369
* The NPT entry for a vCPU's APIC backing page must always be
356370
* present when the vCPU is running in order for Secure AVIC to
@@ -361,7 +375,11 @@ static void savic_setup(void)
361375
* VMRUN, the hypervisor makes use of this information to make sure
362376
* the APIC backing page is mapped in NPT.
363377
*/
364-
res = savic_register_gpa(gpa);
378+
if (hv_isolation_type_snp())
379+
res = hv_set_savic_backing_page(gfn);
380+
else
381+
res = savic_register_gpa(gpa);
382+
365383
if (res != ES_OK)
366384
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SAVIC_FAIL);
367385

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@ static void __init ms_hyperv_init_platform(void)
470470

471471
hv_identify_partition_type();
472472

473+
if (cc_platform_has(CC_ATTR_SNP_SECURE_AVIC))
474+
ms_hyperv.hints |= HV_DEPRECATING_AEOI_RECOMMENDED;
475+
473476
if (ms_hyperv.hints & HV_X64_HYPERV_NESTED) {
474477
hv_nested = true;
475478
pr_info("Hyper-V: running on a nested hypervisor\n");

drivers/hv/hv.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ void hv_synic_enable_regs(unsigned int cpu)
310310
}
311311

312312
hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64);
313+
hv_enable_coco_interrupt(cpu, vmbus_interrupt, true);
313314

314315
/* Setup the shared SINT. */
315316
if (vmbus_irq != -1)
@@ -353,6 +354,7 @@ void hv_synic_disable_regs(unsigned int cpu)
353354
/* Need to correctly cleanup in the case of SMP!!! */
354355
/* Disable the interrupt */
355356
hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
357+
hv_enable_coco_interrupt(cpu, vmbus_interrupt, false);
356358

357359
simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
358360
/*

0 commit comments

Comments
 (0)