Commit b8878e5a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'hyperv-next-signed-20230220' of...

Merge tag 'hyperv-next-signed-20230220' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv updates from Wei Liu:

 - allow Linux to run as the nested root partition for Microsoft
   Hypervisor (Jinank Jain and Nuno Das Neves)

 - clean up the return type of callback functions (Dawei Li)

* tag 'hyperv-next-signed-20230220' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  x86/hyperv: Fix hv_get/set_register for nested bringup
  Drivers: hv: Make remove callback of hyperv driver void returned
  Drivers: hv: Enable vmbus driver for nested root partition
  x86/hyperv: Add an interface to do nested hypercalls
  Drivers: hv: Setup synic registers in case of nested root partition
  x86/hyperv: Add support for detecting nested hypervisor
parents 8bf1a529 b14033a3
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@
/* Recommend using the newer ExProcessorMasks interface */
#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED		BIT(11)

/* Indicates that the hypervisor is nested within a Hyper-V partition. */
#define HV_X64_HYPERV_NESTED				BIT(12)

/* Recommend using enlightened VMCS */
#define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED		BIT(14)

@@ -224,6 +227,17 @@ enum hv_isolation_type {
#define HV_REGISTER_SINT14			0x4000009E
#define HV_REGISTER_SINT15			0x4000009F

/*
 * Define synthetic interrupt controller model specific registers for
 * nested hypervisor.
 */
#define HV_REGISTER_NESTED_SCONTROL            0x40001080
#define HV_REGISTER_NESTED_SVERSION            0x40001081
#define HV_REGISTER_NESTED_SIEFP               0x40001082
#define HV_REGISTER_NESTED_SIMP                0x40001083
#define HV_REGISTER_NESTED_EOM                 0x40001084
#define HV_REGISTER_NESTED_SINT0               0x40001090

/*
 * Synthetic Timer MSRs. Four timers per vcpu.
 */
@@ -368,7 +382,8 @@ struct hv_nested_enlightenments_control {
		__u32 reserved:31;
	} features;
	struct {
		__u32 reserved;
		__u32 inter_partition_comm:1;
		__u32 reserved:31;
	} hypercallControls;
} __packed;

+49 −29
Original line number Diff line number Diff line
@@ -72,10 +72,16 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
	return hv_status;
}

/* Hypercall to the L0 hypervisor */
static inline u64 hv_do_nested_hypercall(u64 control, void *input, void *output)
{
	return hv_do_hypercall(control | HV_HYPERCALL_NESTED, input, output);
}

/* Fast hypercall with 8 bytes of input and no output */
static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1)
{
	u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
	u64 hv_status;

#ifdef CONFIG_X86_64
	{
@@ -103,10 +109,24 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
		return hv_status;
}

static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
{
	u64 control = (u64)code | HV_HYPERCALL_FAST_BIT;

	return _hv_do_fast_hypercall8(control, input1);
}

static inline u64 hv_do_fast_nested_hypercall8(u16 code, u64 input1)
{
	u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;

	return _hv_do_fast_hypercall8(control, input1);
}

/* Fast hypercall with 16 bytes of input */
static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2)
{
	u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
	u64 hv_status;

#ifdef CONFIG_X86_64
	{
@@ -137,6 +157,20 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
	return hv_status;
}

static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
{
	u64 control = (u64)code | HV_HYPERCALL_FAST_BIT;

	return _hv_do_fast_hypercall16(control, input1, input2);
}

static inline u64 hv_do_fast_nested_hypercall16(u16 code, u64 input1, u64 input2)
{
	u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;

	return _hv_do_fast_hypercall16(control, input1, input2);
}

extern struct hv_vp_assist_page **hv_vp_assist_page;

static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
@@ -190,36 +224,20 @@ extern bool hv_isolation_type_snp(void);

static inline bool hv_is_synic_reg(unsigned int reg)
{
	if ((reg >= HV_REGISTER_SCONTROL) &&
	    (reg <= HV_REGISTER_SINT15))
		return true;
	return false;
	return (reg >= HV_REGISTER_SCONTROL) &&
	       (reg <= HV_REGISTER_SINT15);
}

static inline u64 hv_get_register(unsigned int reg)
static inline bool hv_is_sint_reg(unsigned int reg)
{
	u64 value;

	if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
		hv_ghcb_msr_read(reg, &value);
	else
		rdmsrl(reg, value);
	return value;
	return (reg >= HV_REGISTER_SINT0) &&
	       (reg <= HV_REGISTER_SINT15);
}

static inline void hv_set_register(unsigned int reg, u64 value)
{
	if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
		hv_ghcb_msr_write(reg, value);

		/* Write proxy bit via wrmsl instruction */
		if (reg >= HV_REGISTER_SINT0 &&
		    reg <= HV_REGISTER_SINT15)
			wrmsrl(reg, value | 1 << 20);
	} else {
		wrmsrl(reg, value);
	}
}
u64 hv_get_register(unsigned int reg);
void hv_set_register(unsigned int reg, u64 value);
u64 hv_get_non_nested_register(unsigned int reg);
void hv_set_non_nested_register(unsigned int reg, u64 value);

#else /* CONFIG_HYPERV */
static inline void hyperv_init(void) {}
@@ -239,6 +257,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
}
static inline void hv_set_register(unsigned int reg, u64 value) { }
static inline u64 hv_get_register(unsigned int reg) { return 0; }
static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { }
static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages,
					     bool visible)
{
+72 −0
Original line number Diff line number Diff line
@@ -37,9 +37,76 @@

/* Is Linux running as the root partition? */
bool hv_root_partition;
/* Is Linux running on nested Microsoft Hypervisor */
bool hv_nested;
struct ms_hyperv_info ms_hyperv;

#if IS_ENABLED(CONFIG_HYPERV)
static inline unsigned int hv_get_nested_reg(unsigned int reg)
{
	if (hv_is_sint_reg(reg))
		return reg - HV_REGISTER_SINT0 + HV_REGISTER_NESTED_SINT0;

	switch (reg) {
	case HV_REGISTER_SIMP:
		return HV_REGISTER_NESTED_SIMP;
	case HV_REGISTER_SIEFP:
		return HV_REGISTER_NESTED_SIEFP;
	case HV_REGISTER_SVERSION:
		return HV_REGISTER_NESTED_SVERSION;
	case HV_REGISTER_SCONTROL:
		return HV_REGISTER_NESTED_SCONTROL;
	case HV_REGISTER_EOM:
		return HV_REGISTER_NESTED_EOM;
	default:
		return reg;
	}
}

u64 hv_get_non_nested_register(unsigned int reg)
{
	u64 value;

	if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
		hv_ghcb_msr_read(reg, &value);
	else
		rdmsrl(reg, value);
	return value;
}
EXPORT_SYMBOL_GPL(hv_get_non_nested_register);

void hv_set_non_nested_register(unsigned int reg, u64 value)
{
	if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
		hv_ghcb_msr_write(reg, value);

		/* Write proxy bit via wrmsl instruction */
		if (hv_is_sint_reg(reg))
			wrmsrl(reg, value | 1 << 20);
	} else {
		wrmsrl(reg, value);
	}
}
EXPORT_SYMBOL_GPL(hv_set_non_nested_register);

u64 hv_get_register(unsigned int reg)
{
	if (hv_nested)
		reg = hv_get_nested_reg(reg);

	return hv_get_non_nested_register(reg);
}
EXPORT_SYMBOL_GPL(hv_get_register);

void hv_set_register(unsigned int reg, u64 value)
{
	if (hv_nested)
		reg = hv_get_nested_reg(reg);

	hv_set_non_nested_register(reg, value);
}
EXPORT_SYMBOL_GPL(hv_set_register);

static void (*vmbus_handler)(void);
static void (*hv_stimer0_handler)(void);
static void (*hv_kexec_handler)(void);
@@ -301,6 +368,11 @@ static void __init ms_hyperv_init_platform(void)
		pr_info("Hyper-V: running as root partition\n");
	}

	if (ms_hyperv.hints & HV_X64_HYPERV_NESTED) {
		hv_nested = true;
		pr_info("Hyper-V: running on a nested hypervisor\n");
	}

	/*
	 * Extract host information.
	 */
+1 −3
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
	return ret;
}

static int hyperv_vmbus_remove(struct hv_device *hdev)
static void hyperv_vmbus_remove(struct hv_device *hdev)
{
	struct drm_device *dev = hv_get_drvdata(hdev);
	struct hyperv_drm_device *hv = to_hv(dev);
@@ -176,8 +176,6 @@ static int hyperv_vmbus_remove(struct hv_device *hdev)
	hv_set_drvdata(hdev, NULL);

	vmbus_free_mmio(hv->mem->start, hv->fb_size);

	return 0;
}

static int hyperv_vmbus_suspend(struct hv_device *hdev)
+1 −3
Original line number Diff line number Diff line
@@ -524,7 +524,7 @@ static int mousevsc_probe(struct hv_device *device,
}


static int mousevsc_remove(struct hv_device *dev)
static void mousevsc_remove(struct hv_device *dev)
{
	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);

@@ -533,8 +533,6 @@ static int mousevsc_remove(struct hv_device *dev)
	hid_hw_stop(input_dev->hid_device);
	hid_destroy_device(input_dev->hid_device);
	mousevsc_free_device(input_dev);

	return 0;
}

static int mousevsc_suspend(struct hv_device *dev)
Loading