Commit 711ef0c7 authored by xiongmengbiao's avatar xiongmengbiao
Browse files

drivers/crypto/ccp: add ioctl API to pin TKM hugepage

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAMHXY


CVE: NA

---------------------------

When accessing the TKM from the host user space,
DMA operations are performed using hugepages of memory,
which are expected to be permanently fixed in the system.

This patch provides a set of ioctl interfaces to
pin memory pages to prevent migration.

Signed-off-by: default avatarxiongmengbiao <xiongmengbiao@hygon.cn>
parent 4c66b829
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ enum HYGON_PSP_OPCODE {
	HYGON_PSP_MUTEX_ENABLE = 1,
	HYGON_PSP_MUTEX_DISABLE,
	HYGON_VPSP_CTRL_OPT,
	HYGON_PSP_OP_PIN_USER_PAGE,
	HYGON_PSP_OP_UNPIN_USER_PAGE,
	HYGON_PSP_OPCODE_MAX_NR,
};

@@ -299,6 +301,67 @@ static int vpsp_set_gpa_range(u64 gpa_start, u64 gpa_end)
	return 0;
}

/**
 * Try to pin a page
 *
 * @vaddr: the userspace virtual address, must be aligned to PAGE_SIZE
 */
static int psp_pin_user_page(u64 vaddr)
{
	struct page *page;
	long npinned = 0;
	int ref_count = 0;

	// check must be aligned to PAGE_SIZE
	if (vaddr & (PAGE_SIZE - 1)) {
		pr_err("vaddr %llx not aligned to 0x%lx\n", vaddr, PAGE_SIZE);
		return -EFAULT;
	}

	npinned = pin_user_pages_fast(vaddr, 1, FOLL_WRITE, &page);
	if (npinned != 1) {
		pr_err("PSP: pin_user_pages_fast fail\n");
		return -ENOMEM;
	}

	ref_count = page_ref_count(page);
	pr_debug("pin user page with address %llx, page ref_count %d\n", vaddr, ref_count);
	return 0;
}

/**
 * Try to unpin a page
 *
 * @vaddr: the userspace virtual address, must be aligned to PAGE_SIZE
 */
static int psp_unpin_user_page(u64 vaddr)
{
	struct page *page;
	long npinned = 0;
	int ref_count = 0;

	// check must be aligned to PAGE_SIZE
	if (vaddr & (PAGE_SIZE - 1)) {
		pr_err("vaddr %llx not aligned to 0x%lx\n", vaddr, PAGE_SIZE);
		return -EFAULT;
	}

	// page reference count increment by 1
	npinned = get_user_pages_fast(vaddr, 1, FOLL_WRITE, &page);
	if (npinned != 1) {
		pr_err("PSP: pin_user_pages_fast fail\n");
		return -ENOMEM;
	}

	// page reference count decrement by 2
	put_page(page);
	put_page(page);

	ref_count = page_ref_count(page);
	pr_debug("unpin user page with address %llx, page ref_count %d\n", vaddr, ref_count);
	return 0;
}

static int do_vpsp_op_ioctl(struct vpsp_dev_ctrl *ctrl)
{
	int ret = 0;
@@ -378,6 +441,14 @@ static long ioctl_psp(struct file *file, unsigned int ioctl, unsigned long arg)
			return -EFAULT;
		break;

	case HYGON_PSP_OP_PIN_USER_PAGE:
		ret = psp_pin_user_page((u64)arg);
		break;

	case HYGON_PSP_OP_UNPIN_USER_PAGE:
		ret = psp_unpin_user_page((u64)arg);
		break;

	default:
		pr_info("%s: invalid ioctl number: %d\n", __func__, opcode);
		return -EINVAL;
+1 −1
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ static int kvm_pv_psp_cmd_pre_op(struct kvm_vpsp *vpsp, gpa_t data_gpa,
		return -EFAULT;

	data_size = psp_head.buf_size;
	if (check_psp_mem_range(NULL, data_gpa, data_size))
	if (check_psp_mem_range(NULL, (void *)data_gpa, data_size))
		return -EFAULT;

	data = kzalloc(data_size, GFP_KERNEL);