mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +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
5 changed files with 94 additions and 2 deletions
|
@ -19,10 +19,85 @@
|
||||||
#include <asm/hypervisor.h>
|
#include <asm/hypervisor.h>
|
||||||
|
|
||||||
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||||
|
|
||||||
|
#define GHCB_USAGE_HYPERV_CALL 1
|
||||||
|
|
||||||
union hv_ghcb {
|
union hv_ghcb {
|
||||||
struct ghcb 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);
|
} __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)
|
void hv_ghcb_msr_write(u64 msr, u64 value)
|
||||||
{
|
{
|
||||||
union hv_ghcb *hv_ghcb;
|
union hv_ghcb *hv_ghcb;
|
||||||
|
|
|
@ -447,6 +447,10 @@ void vmbus_set_event(struct vmbus_channel *channel)
|
||||||
|
|
||||||
++channel->sig_events;
|
++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);
|
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;
|
aligned_msg->payload_size = payload_size;
|
||||||
memcpy((void *)aligned_msg->payload, payload, 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
|
/* Preemption must remain disabled until after the hypercall
|
||||||
* so some other thread can't get scheduled onto this cpu and
|
* 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);
|
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);
|
enum hv_isolation_type hv_get_isolation_type(void);
|
||||||
bool hv_is_isolation_supported(void);
|
bool hv_is_isolation_supported(void);
|
||||||
bool hv_isolation_type_snp(void);
|
bool hv_isolation_type_snp(void);
|
||||||
|
u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);
|
||||||
void hyperv_cleanup(void);
|
void hyperv_cleanup(void);
|
||||||
bool hv_query_ext_cap(u64 cap_query);
|
bool hv_query_ext_cap(u64 cap_query);
|
||||||
#else /* CONFIG_HYPERV */
|
#else /* CONFIG_HYPERV */
|
||||||
|
|
Loading…
Add table
Reference in a new issue