Unverified Commit 53b3b043 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!12280 fix Hygon TKM may execute fail in CSV VM

Merge Pull Request from: @xisme 
 
1. The Hygon platform indirectly accesses the `sev_cmd_mutex` variable through `hygon_psp_hooks`. However, on non-Hygon platforms (such as AMD), `hygon_psp_hooks` is not initialized, so `sev_cmd_mutex` should be accessed directly.

issue: https://gitee.com/openeuler/kernel/issues/IAYIA8

2. TKM uses gfn_to_pfn to obtain HPA from GPA. Each call will increase the ref_count of the page corresponding to pfn by 1, so the ref_count count needs to be restored after the call is successful.

issue: https://gitee.com/openeuler/kernel/issues/IAYITA 
 
Link:https://gitee.com/openeuler/kernel/pulls/12280

 

Reviewed-by: default avatarZhang Peng <zhangpeng362@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 218c454d 58acd1b8
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (input.cmd > CSV_MAX)
		return -EINVAL;

	if (is_vendor_hygon() && mutex_enabled) {
	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -239,7 +239,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
		 * Release the mutex before calling the native ioctl function
		 * because it will acquires the mutex.
		 */
		if (is_vendor_hygon() && mutex_enabled)
		if (mutex_enabled)
			psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
		else
			mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -249,7 +249,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
		ret = -EFAULT;

	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -412,7 +412,7 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (is_vendor_hygon() && mutex_enabled) {
	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -431,7 +431,7 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
	csv_comm_mode = CSV_COMM_MAILBOX_ON;

cmd_unlock:
	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -819,7 +819,10 @@ static int vpsp_psp_mutex_trylock(void)
{
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled)
		return psp_mutex_trylock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		return mutex_trylock(hygon_psp_hooks.sev_cmd_mutex);
@@ -829,7 +832,10 @@ static int vpsp_psp_mutex_unlock(void)
{
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -845,6 +851,9 @@ static int __vpsp_ring_buffer_enter_locked(int *error)
	struct csv_ringbuffer_queue *hi_queue;
	struct sev_device *sev = psp_master->sev_data;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (csv_comm_mode == CSV_COMM_RINGBUFFER_ON)
		return -EEXIST;

@@ -881,7 +890,7 @@ static int __vpsp_do_ringbuf_cmds_locked(int *psp_ret, uint8_t prio, int index)
	unsigned int rb_ctl;
	struct sev_device *sev;

	if (!psp)
	if (!psp || !hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (*hygon_psp_hooks.psp_dead)
@@ -944,6 +953,9 @@ static int vpsp_do_ringbuf_cmds_locked(int *psp_ret, uint8_t prio, int index)
	struct sev_user_data_status data;
	int rc;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	rc = __vpsp_ring_buffer_enter_locked(psp_ret);
	if (rc)
		goto end;
@@ -1055,7 +1067,7 @@ static int __vpsp_do_cmd_locked(int cmd, phys_addr_t phy_addr, int *psp_ret)
	unsigned int phys_lsb, phys_msb;
	unsigned int reg, ret = 0;

	if (!psp || !psp->sev_data)
	if (!psp || !psp->sev_data || !hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (*hygon_psp_hooks.psp_dead)
@@ -1109,7 +1121,10 @@ int vpsp_do_cmd(int cmd, phys_addr_t phy_addr, int *psp_ret)
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled) {
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					PSP_MUTEX_TIMEOUT) != 1) {
			return -EBUSY;
@@ -1120,7 +1135,7 @@ int vpsp_do_cmd(int cmd, phys_addr_t phy_addr, int *psp_ret)

	rc = __vpsp_do_cmd_locked(cmd, phy_addr, psp_ret);

	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -1138,6 +1153,9 @@ int vpsp_try_get_result(uint8_t prio, uint32_t index, phys_addr_t phy_addr,
	int ret = 0;
	struct csv_cmdptr_entry cmd = {0};

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	/* Get the retult directly if the command has been executed */
	if (index >= 0 && vpsp_get_cmd_status(prio, index) !=
			VPSP_CMD_STATUS_RUNNING) {
@@ -1202,6 +1220,9 @@ int vpsp_try_do_cmd(int cmd, phys_addr_t phy_addr, struct vpsp_ret *psp_ret)
	int index = -1;
	uint8_t prio = CSV_COMMAND_PRIORITY_LOW;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	/* ringbuffer mode check and parse command prio*/
	rb_supported = vpsp_rb_check_and_cmd_prio_parse(&prio,
			(struct vpsp_cmd *)&cmd);
+13 −2
Original line number Diff line number Diff line
@@ -401,6 +401,9 @@ static long ioctl_psp(struct file *file, unsigned int ioctl, unsigned long arg)
	struct vpsp_dev_ctrl vpsp_ctrl_op;
	int ret = -EFAULT;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (_IOC_TYPE(ioctl) != HYGON_PSP_IOC_TYPE) {
		pr_info("%s: invalid ioctl type: 0x%x\n", __func__, _IOC_TYPE(ioctl));
		return -EINVAL;
@@ -469,6 +472,9 @@ int hygon_psp_additional_setup(struct sp_device *sp)
	struct device *dev = sp->dev;
	int ret = 0;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (!psp_misc) {
		struct miscdevice *misc;

@@ -592,7 +598,12 @@ static int __psp_do_cmd_locked(int cmd, void *data, int *psp_ret)
int psp_do_cmd(int cmd, void *data, int *psp_ret)
{
	int rc;
	if (is_vendor_hygon()) {
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -601,7 +612,7 @@ int psp_do_cmd(int cmd, void *data, int *psp_ret)
	}

	rc = __psp_do_cmd_locked(cmd, data, psp_ret);
	if (is_vendor_hygon())
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
+25 −1
Original line number Diff line number Diff line
@@ -220,12 +220,28 @@ static phys_addr_t gpa_to_hpa(struct kvm_vpsp *vpsp, unsigned long data_gpa)
	phys_addr_t hpa = 0;
	unsigned long pfn = vpsp->gfn_to_pfn(vpsp->kvm, data_gpa >> PAGE_SHIFT);
	unsigned long me_mask = sme_get_me_mask();
	struct page *page;

	if (me_mask == 0 && vpsp->is_csv_guest)
		me_mask = vpsp_get_me_mask();

	if (!is_error_pfn(pfn))
		hpa = ((pfn << PAGE_SHIFT) + offset_in_page(data_gpa)) | me_mask;
	else {
		pr_err("[%s] pfn: %lx is invalid, gpa %lx",
				__func__, pfn, data_gpa);
		return 0;
	}

	/*
	 * Using gfn_to_pfn causes the refcount to increment
	 * atomically by one, which needs to be released.
	 */
	page = pfn_to_page(pfn);
	if (PageCompound(page))
		page = compound_head(page);

	put_page(page);

	pr_debug("gpa %lx, hpa %llx\n", data_gpa, hpa);
	return hpa;
@@ -343,6 +359,7 @@ int kvm_pv_psp_forward_op(struct kvm_vpsp *vpsp, uint32_t cmd,
	struct vpsp_context *vpsp_ctx = NULL;
	struct vpsp_cmd *vcmd = (struct vpsp_cmd *)&cmd;
	uint8_t prio = CSV_COMMAND_PRIORITY_LOW;
	phys_addr_t hpa;

	vpsp_get_context(&vpsp_ctx, vpsp->kvm->userspace_pid);

@@ -363,7 +380,14 @@ int kvm_pv_psp_forward_op(struct kvm_vpsp *vpsp, uint32_t cmd,
		vid = vpsp_ctx->vid;

	*((uint32_t *)&psp_async) = psp_ret;
	data_hpa = PUT_PSP_VID(gpa_to_hpa(vpsp, data_gpa), vid);

	hpa = gpa_to_hpa(vpsp, data_gpa);
	if (unlikely(!hpa)) {
		ret = -EFAULT;
		goto end;
	}

	data_hpa = PUT_PSP_VID(hpa, vid);

	switch (psp_async.status) {
	case VPSP_INIT:
+12 −5
Original line number Diff line number Diff line
@@ -200,11 +200,6 @@ int psp_dev_init(struct sp_device *sp)

	/* Request an irq */
	if (is_vendor_hygon()) {
		ret = hygon_psp_additional_setup(sp);
		if (ret) {
			dev_err(dev, "psp: unable to do additional setup\n");
			goto e_err;
		}
		ret = sp_request_hygon_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
	} else {
		ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
@@ -222,6 +217,18 @@ int psp_dev_init(struct sp_device *sp)
	if (ret)
		goto e_irq;

	/**
	 * hygon_psp_additional_setup() needs to wait for
	 * sev_dev_install_hooks() to complete before it can be called.
	 */
	if (is_vendor_hygon()) {
		ret = hygon_psp_additional_setup(sp);
		if (ret) {
			dev_err(dev, "psp: unable to do additional setup\n");
			goto e_irq;
		}
	}

	/* Enable interrupt */
	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);

+8 −8
Original line number Diff line number Diff line
@@ -415,13 +415,13 @@ static int sev_do_cmd(int cmd, void *data, int *psp_ret)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_do_cmd_locked(cmd, data, psp_ret);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -546,13 +546,13 @@ int sev_platform_init(int *error)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_platform_init_locked(error);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -596,13 +596,13 @@ static int sev_platform_shutdown(int *error)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_platform_shutdown_locked(NULL);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -1168,7 +1168,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}

	switch (input.cmd) {
@@ -1212,7 +1212,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return ret;
}