Skip to content

Commit

Permalink
x86/Hyper-V: Add new hvcall guest address host visibility support
Browse files Browse the repository at this point in the history
Add new hvcall guest address host visibility and make buffer
visible to host when create gpadl.

Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
  • Loading branch information
Tianyu Lan authored and Tianyu Lan committed Jan 15, 2021
1 parent e697bc5 commit deb6dc9
Show file tree
Hide file tree
Showing 6 changed files with 623 additions and 20 deletions.
17 changes: 17 additions & 0 deletions arch/x86/include/asm/hyperv-tlfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@
#define HV_X64_DEBUGGING BIT(11)
#define HV_X64_CPU_POWER_MANAGEMENT BIT(12)

/* Isolation VM flag */
#define HV_X64_PARTITION_ISOLATION BIT(22)

/*
* Feature identification. EDX indicates which miscellaneous features
* are available to the partition.
Expand Down Expand Up @@ -382,6 +385,7 @@ struct hv_tsc_emulation_status {
#define HVCALL_SIGNAL_EVENT 0x005d
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db

#define HV_X64_MSR_VP_ASSIST_PAGE_ENABLE 0x00000001
#define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT 12
Expand Down Expand Up @@ -912,4 +916,17 @@ struct hv_tlb_flush_ex {
struct hv_partition_assist_pg {
u32 tlb_lock_count;
};
/* All input parameters should be in single page. */
#define HV_MAX_MODIFY_GPA_REP_COUNT \
((PAGE_SIZE - 2 * sizeof(u64)) / (sizeof(u64)))

/* HvCallModifySparseGpaPageHostVisibility hypercall */
struct hv_input_modify_sparse_gpa_page_host_visibility {
u64 partition_id;
u32 host_visibility:2;
u32 reserved0:30;
u32 reserved1;
u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT];
} __packed;

#endif
6 changes: 6 additions & 0 deletions arch/x86/include/asm/mshyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ bool hv_vcpu_is_preempted(int vcpu);
static inline void hv_apic_init(void) {}
#endif

int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility);
#else /* CONFIG_HYPERV */
static inline void hyperv_init(void) {}
static inline void hyperv_setup_mmu_ops(void) {}
Expand All @@ -262,4 +263,9 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,

#include <asm-generic/mshyperv.h>

static inline bool hv_partition_is_isolated(void)
{
return (ms_hyperv.partition_flags & HV_X64_PARTITION_ISOLATION);
}

#endif
52 changes: 50 additions & 2 deletions arch/x86/kernel/cpu/mshyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <asm/nmi.h>
#include <clocksource/hyperv_timer.h>

#define HV_PARTITION_ID_SELF ((u64)-1)

struct ms_hyperv_info ms_hyperv;
EXPORT_SYMBOL_GPL(ms_hyperv);

Expand Down Expand Up @@ -224,11 +226,13 @@ static void __init ms_hyperv_init_platform(void)
* Extract the features and hints
*/
ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES);
ms_hyperv.partition_flags = cpuid_ebx(HYPERV_CPUID_FEATURES);
ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);

pr_info("Hyper-V: features 0x%x, hints 0x%x\n",
ms_hyperv.features, ms_hyperv.hints);

pr_info("Hyper-V: features 0x%x, partition flags: 0x%x, hints 0x%x.\n",
ms_hyperv.features, ms_hyperv.partition_flags, ms_hyperv.hints);

ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS);
ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS);
Expand Down Expand Up @@ -355,6 +359,50 @@ void hv_setup_sched_clock(void *sched_clock)
#endif
}

int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility)
{
struct hv_input_modify_sparse_gpa_page_host_visibility **input_pcpu;
struct hv_input_modify_sparse_gpa_page_host_visibility *input;
u16 pages_processed;
u64 hv_status;
unsigned long flags;

/* no-op if partition isolation is not enabled */
if (!hv_partition_is_isolated())
return 0;

if (count > HV_MAX_MODIFY_GPA_REP_COUNT) {
pr_err("Hyper-V: GPA count:%d exceeds supported:%lu\n", count,
HV_MAX_MODIFY_GPA_REP_COUNT);
return -EINVAL;
}

local_irq_save(flags);
input_pcpu = (struct hv_input_modify_sparse_gpa_page_host_visibility **)
this_cpu_ptr(hyperv_pcpu_input_arg);
input = *input_pcpu;
if (unlikely(!input)) {
local_irq_restore(flags);
return -1;
}

input->partition_id = HV_PARTITION_ID_SELF;
input->host_visibility = visibility;
input->reserved0 = 0;
input->reserved1 = 0;
memcpy((void *)input->gpa_page_list, pfn, count * sizeof(*pfn));
hv_status = hv_do_rep_hypercall(
HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY, count,
0, input, &pages_processed);
local_irq_restore(flags);

if (!(hv_status & HV_HYPERCALL_RESULT_MASK))
return 0;

return -EFAULT;
}
EXPORT_SYMBOL(hv_mark_gpa_visibility);

const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.name = "Microsoft Hyper-V",
.detect = ms_hyperv_platform,
Expand Down
69 changes: 51 additions & 18 deletions drivers/hv/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,10 @@ static int create_gpadl_header(void *kbuffer, u32 size,
struct vmbus_channel_gpadl_body *gpadl_body;
struct vmbus_channel_msginfo *msgheader;
struct vmbus_channel_msginfo *msgbody = NULL;
struct vmbus_channel_msginfo *pos = NULL;
struct vmbus_channel_msginfo *tmp = NULL;
u32 msgsize;

int ret = -ENOMEM;
int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;

pagecount = size >> PAGE_SHIFT;
Expand Down Expand Up @@ -339,6 +341,10 @@ static int create_gpadl_header(void *kbuffer, u32 size,
gpadl_header->range[0].pfn_array[i] = virt_to_hvpfn(
kbuffer + PAGE_SIZE * i);
*msginfo = msgheader;
ret = hv_mark_gpa_visibility(i,
gpadl_header->range[0].pfn_array, visibility);
if (ret < 0)
goto nomem;

pfnsum = pfncount;
pfnleft = pagecount - pfncount;
Expand All @@ -360,22 +366,8 @@ static int create_gpadl_header(void *kbuffer, u32 size,
pfncurr * sizeof(u64);
msgbody = kzalloc(msgsize, GFP_KERNEL);

if (!msgbody) {
struct vmbus_channel_msginfo *pos = NULL;
struct vmbus_channel_msginfo *tmp = NULL;
/*
* Free up all the allocated messages.
*/
list_for_each_entry_safe(pos, tmp,
&msgheader->submsglist,
msglistentry) {

list_del(&pos->msglistentry);
kfree(pos);
}

goto nomem;
}
if (!msgbody)
goto Cleanvisibility;

msgbody->msgsize = msgsize;
gpadl_body =
Expand All @@ -390,6 +382,10 @@ static int create_gpadl_header(void *kbuffer, u32 size,
for (i = 0; i < pfncurr; i++)
gpadl_body->pfn[i] = virt_to_hvpfn(
kbuffer + PAGE_SIZE * (pfnsum + i));
ret = hv_mark_gpa_visibility(i, gpadl_body->pfn,
visibility);
if (ret < 0)
goto Cleanvisibility;

/* add to msg header */
list_add_tail(&msgbody->msglistentry,
Expand Down Expand Up @@ -420,14 +416,51 @@ static int create_gpadl_header(void *kbuffer, u32 size,
gpadl_header->range[0].pfn_array[i] = virt_to_hvpfn(
kbuffer + PAGE_SIZE * i);

ret = hv_mark_gpa_visibility(i, gpadl_header->range[0].pfn_array,
visibility);
if (ret < 0)
goto nomem;
*msginfo = msgheader;
}

return 0;

Cleanvisibility:
/*
* Free up all the allocated messages.
*/
list_for_each_entry_safe(pos, tmp,
&msgheader->submsglist,
msglistentry) {

list_del(&pos->msglistentry);
kfree(pos);
}

/* Set host visibility back to not-visible. */
pfnleft = pfnsum;
pfnsum = 0;
while (pfnleft) {
if (pfnleft > pfncount)
pfncurr = pfncount;
else
pfncurr = pfnleft;

for (i = 0; i < pfncurr; i++)
gpadl_body->pfn[i] = virt_to_hvpfn(
kbuffer + PAGE_SIZE * (pfnsum + i));
hv_mark_gpa_visibility(i, gpadl_body->pfn,
VMBUS_PAGE_NOT_VISIBLE);

pfnsum += pfncurr;
pfnleft -= pfncurr;
}

nomem:

kfree(msgheader);
kfree(msgbody);
return -ENOMEM;
return ret;
}

/*
Expand Down
Loading

0 comments on commit deb6dc9

Please sign in to comment.