mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
x86/hyperv: Add ghcb hvcall support for SNP VM
hyperv provides ghcb hvcall to handle VMBus HVCALL_SIGNAL_EVENT and HVCALL_POST_MESSAGE msg in SNP Isolation VM. Add such support. Reviewed-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com> Link: https://lore.kernel.org/r/20211025122116.264793-8-ltykernel@gmail.com Signed-off-by: Wei Liu <wei.liu@kernel.org>
This commit is contained in:
parent
faff44069f
commit
20c89a559e
@ -19,10 +19,85 @@
|
||||
#include <asm/hypervisor.h>
|
||||
|
||||
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||
|
||||
#define GHCB_USAGE_HYPERV_CALL 1
|
||||
|
||||
union hv_ghcb {
|
||||
struct ghcb ghcb;
|
||||
struct {
|
||||
u64 hypercalldata[509];
|
||||
u64 outputgpa;
|
||||
union {
|
||||
union {
|
||||
struct {
|
||||
u32 callcode : 16;
|
||||
u32 isfast : 1;
|
||||
u32 reserved1 : 14;
|
||||
u32 isnested : 1;
|
||||
u32 countofelements : 12;
|
||||
u32 reserved2 : 4;
|
||||
u32 repstartindex : 12;
|
||||
u32 reserved3 : 4;
|
||||
};
|
||||
u64 asuint64;
|
||||
} hypercallinput;
|
||||
union {
|
||||
struct {
|
||||
u16 callstatus;
|
||||
u16 reserved1;
|
||||
u32 elementsprocessed : 12;
|
||||
u32 reserved2 : 20;
|
||||
};
|
||||
u64 asunit64;
|
||||
} hypercalloutput;
|
||||
};
|
||||
u64 reserved2;
|
||||
} hypercall;
|
||||
} __packed __aligned(HV_HYP_PAGE_SIZE);
|
||||
|
||||
u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size)
|
||||
{
|
||||
union hv_ghcb *hv_ghcb;
|
||||
void **ghcb_base;
|
||||
unsigned long flags;
|
||||
u64 status;
|
||||
|
||||
if (!hv_ghcb_pg)
|
||||
return -EFAULT;
|
||||
|
||||
WARN_ON(in_nmi());
|
||||
|
||||
local_irq_save(flags);
|
||||
ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg);
|
||||
hv_ghcb = (union hv_ghcb *)*ghcb_base;
|
||||
if (!hv_ghcb) {
|
||||
local_irq_restore(flags);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
hv_ghcb->ghcb.protocol_version = GHCB_PROTOCOL_MAX;
|
||||
hv_ghcb->ghcb.ghcb_usage = GHCB_USAGE_HYPERV_CALL;
|
||||
|
||||
hv_ghcb->hypercall.outputgpa = (u64)output;
|
||||
hv_ghcb->hypercall.hypercallinput.asuint64 = 0;
|
||||
hv_ghcb->hypercall.hypercallinput.callcode = control;
|
||||
|
||||
if (input_size)
|
||||
memcpy(hv_ghcb->hypercall.hypercalldata, input, input_size);
|
||||
|
||||
VMGEXIT();
|
||||
|
||||
hv_ghcb->ghcb.ghcb_usage = 0xffffffff;
|
||||
memset(hv_ghcb->ghcb.save.valid_bitmap, 0,
|
||||
sizeof(hv_ghcb->ghcb.save.valid_bitmap));
|
||||
|
||||
status = hv_ghcb->hypercall.hypercalloutput.callstatus;
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void hv_ghcb_msr_write(u64 msr, u64 value)
|
||||
{
|
||||
union hv_ghcb *hv_ghcb;
|
||||
|
@ -447,6 +447,10 @@ void vmbus_set_event(struct vmbus_channel *channel)
|
||||
|
||||
++channel->sig_events;
|
||||
|
||||
hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event);
|
||||
if (hv_isolation_type_snp())
|
||||
hv_ghcb_hypercall(HVCALL_SIGNAL_EVENT, &channel->sig_event,
|
||||
NULL, sizeof(channel->sig_event));
|
||||
else
|
||||
hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_set_event);
|
||||
|
@ -98,7 +98,13 @@ int hv_post_message(union hv_connection_id connection_id,
|
||||
aligned_msg->payload_size = payload_size;
|
||||
memcpy((void *)aligned_msg->payload, payload, payload_size);
|
||||
|
||||
status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL);
|
||||
if (hv_isolation_type_snp())
|
||||
status = hv_ghcb_hypercall(HVCALL_POST_MESSAGE,
|
||||
(void *)aligned_msg, NULL,
|
||||
sizeof(*aligned_msg));
|
||||
else
|
||||
status = hv_do_hypercall(HVCALL_POST_MESSAGE,
|
||||
aligned_msg, NULL);
|
||||
|
||||
/* Preemption must remain disabled until after the hypercall
|
||||
* so some other thread can't get scheduled onto this cpu and
|
||||
|
@ -289,3 +289,9 @@ void __weak hyperv_cleanup(void)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hyperv_cleanup);
|
||||
|
||||
u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size)
|
||||
{
|
||||
return HV_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_ghcb_hypercall);
|
||||
|
@ -266,6 +266,7 @@ bool hv_is_hibernation_supported(void);
|
||||
enum hv_isolation_type hv_get_isolation_type(void);
|
||||
bool hv_is_isolation_supported(void);
|
||||
bool hv_isolation_type_snp(void);
|
||||
u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);
|
||||
void hyperv_cleanup(void);
|
||||
bool hv_query_ext_cap(u64 cap_query);
|
||||
#else /* CONFIG_HYPERV */
|
||||
|
Loading…
Reference in New Issue
Block a user