xref: /openbmc/linux/drivers/s390/char/uvdevice.c (revision 2d8a26ac)
14689752cSSteffen Eiden // SPDX-License-Identifier: GPL-2.0
24689752cSSteffen Eiden /*
34689752cSSteffen Eiden  *  Copyright IBM Corp. 2022
44689752cSSteffen Eiden  *  Author(s): Steffen Eiden <seiden@linux.ibm.com>
54689752cSSteffen Eiden  *
64689752cSSteffen Eiden  *  This file provides a Linux misc device to give userspace access to some
74689752cSSteffen Eiden  *  Ultravisor (UV) functions. The device only accepts IOCTLs and will only
84689752cSSteffen Eiden  *  be present if the Ultravisor facility (158) is present.
94689752cSSteffen Eiden  *
104689752cSSteffen Eiden  *  When userspace sends a valid IOCTL uvdevice will copy the input data to
114689752cSSteffen Eiden  *  kernel space, do some basic validity checks to avoid kernel/system
124689752cSSteffen Eiden  *  corruption. Any other check that the Ultravisor does will not be done by
134689752cSSteffen Eiden  *  the uvdevice to keep changes minimal when adding new functionalities
144689752cSSteffen Eiden  *  to existing UV-calls.
154689752cSSteffen Eiden  *  After the checks uvdevice builds a corresponding
164689752cSSteffen Eiden  *  Ultravisor Call Control Block, and sends the request to the Ultravisor.
174689752cSSteffen Eiden  *  Then, it copies the response, including the return codes, back to userspace.
184689752cSSteffen Eiden  *  It is the responsibility of the userspace to check for any error issued
194689752cSSteffen Eiden  *  by UV and to interpret the UV response. The uvdevice acts as a communication
204689752cSSteffen Eiden  *  channel for userspace to the Ultravisor.
214689752cSSteffen Eiden  */
224689752cSSteffen Eiden 
234689752cSSteffen Eiden #include <linux/module.h>
244689752cSSteffen Eiden #include <linux/kernel.h>
254689752cSSteffen Eiden #include <linux/miscdevice.h>
264689752cSSteffen Eiden #include <linux/types.h>
274689752cSSteffen Eiden #include <linux/stddef.h>
284689752cSSteffen Eiden #include <linux/vmalloc.h>
294689752cSSteffen Eiden #include <linux/slab.h>
305fcd0d8aSSteffen Eiden #include <linux/cpufeature.h>
314689752cSSteffen Eiden 
324689752cSSteffen Eiden #include <asm/uvdevice.h>
334689752cSSteffen Eiden #include <asm/uv.h>
344689752cSSteffen Eiden 
35ea9d9716SSteffen Eiden #define BIT_UVIO_INTERNAL U32_MAX
36ea9d9716SSteffen Eiden /* Mapping from IOCTL-nr to UVC-bit */
37ea9d9716SSteffen Eiden static const u32 ioctl_nr_to_uvc_bit[] __initconst = {
38ea9d9716SSteffen Eiden 	[UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL,
39ea9d9716SSteffen Eiden 	[UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST,
4044567ca2SSteffen Eiden 	[UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET,
41b96b3ce2SSteffen Eiden 	[UVIO_IOCTL_LIST_SECRETS_NR] = BIT_UVC_CMD_LIST_SECRETS,
42*2d8a26acSSteffen Eiden 	[UVIO_IOCTL_LOCK_SECRETS_NR] = BIT_UVC_CMD_LOCK_SECRETS,
43ea9d9716SSteffen Eiden };
44ea9d9716SSteffen Eiden 
45ea9d9716SSteffen Eiden static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS);
46ea9d9716SSteffen Eiden 
47ea9d9716SSteffen Eiden static struct uvio_uvdev_info uvdev_info = {
48ea9d9716SSteffen Eiden 	.supp_uvio_cmds = GENMASK_ULL(UVIO_IOCTL_NUM_IOCTLS - 1, 0),
49ea9d9716SSteffen Eiden };
50ea9d9716SSteffen Eiden 
set_supp_uv_cmds(unsigned long * supp_uv_cmds)51ea9d9716SSteffen Eiden static void __init set_supp_uv_cmds(unsigned long *supp_uv_cmds)
52ea9d9716SSteffen Eiden {
53ea9d9716SSteffen Eiden 	int i;
54ea9d9716SSteffen Eiden 
55ea9d9716SSteffen Eiden 	for (i = 0; i < UVIO_IOCTL_NUM_IOCTLS; i++) {
56ea9d9716SSteffen Eiden 		if (ioctl_nr_to_uvc_bit[i] == BIT_UVIO_INTERNAL)
57ea9d9716SSteffen Eiden 			continue;
58ea9d9716SSteffen Eiden 		if (!test_bit_inv(ioctl_nr_to_uvc_bit[i], uv_info.inst_calls_list))
59ea9d9716SSteffen Eiden 			continue;
60ea9d9716SSteffen Eiden 		__set_bit(i, supp_uv_cmds);
61ea9d9716SSteffen Eiden 	}
62ea9d9716SSteffen Eiden }
63ea9d9716SSteffen Eiden 
64ea9d9716SSteffen Eiden /**
65ea9d9716SSteffen Eiden  * uvio_uvdev_info() - get information about the uvdevice
66ea9d9716SSteffen Eiden  *
67ea9d9716SSteffen Eiden  * @uv_ioctl: ioctl control block
68ea9d9716SSteffen Eiden  *
69ea9d9716SSteffen Eiden  * Lists all IOCTLs that are supported by this uvdevice
70ea9d9716SSteffen Eiden  */
uvio_uvdev_info(struct uvio_ioctl_cb * uv_ioctl)71ea9d9716SSteffen Eiden static int uvio_uvdev_info(struct uvio_ioctl_cb *uv_ioctl)
72ea9d9716SSteffen Eiden {
73ea9d9716SSteffen Eiden 	void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr;
74ea9d9716SSteffen Eiden 
75ea9d9716SSteffen Eiden 	if (uv_ioctl->argument_len < sizeof(uvdev_info))
76ea9d9716SSteffen Eiden 		return -EINVAL;
77ea9d9716SSteffen Eiden 	if (copy_to_user(user_buf_arg, &uvdev_info, sizeof(uvdev_info)))
78ea9d9716SSteffen Eiden 		return -EFAULT;
79ea9d9716SSteffen Eiden 
80ea9d9716SSteffen Eiden 	uv_ioctl->uv_rc = UVC_RC_EXECUTED;
81ea9d9716SSteffen Eiden 	return 0;
82ea9d9716SSteffen Eiden }
83ea9d9716SSteffen Eiden 
uvio_build_uvcb_attest(struct uv_cb_attest * uvcb_attest,u8 * arcb,u8 * meas,u8 * add_data,struct uvio_attest * uvio_attest)844689752cSSteffen Eiden static int uvio_build_uvcb_attest(struct uv_cb_attest *uvcb_attest, u8 *arcb,
854689752cSSteffen Eiden 				  u8 *meas, u8 *add_data, struct uvio_attest *uvio_attest)
864689752cSSteffen Eiden {
874689752cSSteffen Eiden 	void __user *user_buf_arcb = (void __user *)uvio_attest->arcb_addr;
884689752cSSteffen Eiden 
894689752cSSteffen Eiden 	if (copy_from_user(arcb, user_buf_arcb, uvio_attest->arcb_len))
904689752cSSteffen Eiden 		return -EFAULT;
914689752cSSteffen Eiden 
924689752cSSteffen Eiden 	uvcb_attest->header.len = sizeof(*uvcb_attest);
934689752cSSteffen Eiden 	uvcb_attest->header.cmd = UVC_CMD_RETR_ATTEST;
944689752cSSteffen Eiden 	uvcb_attest->arcb_addr = (u64)arcb;
954689752cSSteffen Eiden 	uvcb_attest->cont_token = 0;
964689752cSSteffen Eiden 	uvcb_attest->user_data_len = uvio_attest->user_data_len;
974689752cSSteffen Eiden 	memcpy(uvcb_attest->user_data, uvio_attest->user_data, sizeof(uvcb_attest->user_data));
984689752cSSteffen Eiden 	uvcb_attest->meas_len = uvio_attest->meas_len;
994689752cSSteffen Eiden 	uvcb_attest->meas_addr = (u64)meas;
1004689752cSSteffen Eiden 	uvcb_attest->add_data_len = uvio_attest->add_data_len;
1014689752cSSteffen Eiden 	uvcb_attest->add_data_addr = (u64)add_data;
1024689752cSSteffen Eiden 
1034689752cSSteffen Eiden 	return 0;
1044689752cSSteffen Eiden }
1054689752cSSteffen Eiden 
uvio_copy_attest_result_to_user(struct uv_cb_attest * uvcb_attest,struct uvio_ioctl_cb * uv_ioctl,u8 * measurement,u8 * add_data,struct uvio_attest * uvio_attest)1064689752cSSteffen Eiden static int uvio_copy_attest_result_to_user(struct uv_cb_attest *uvcb_attest,
1074689752cSSteffen Eiden 					   struct uvio_ioctl_cb *uv_ioctl,
1084689752cSSteffen Eiden 					   u8 *measurement, u8 *add_data,
1094689752cSSteffen Eiden 					   struct uvio_attest *uvio_attest)
1104689752cSSteffen Eiden {
1114689752cSSteffen Eiden 	struct uvio_attest __user *user_uvio_attest = (void __user *)uv_ioctl->argument_addr;
1124689752cSSteffen Eiden 	void __user *user_buf_add = (void __user *)uvio_attest->add_data_addr;
1134689752cSSteffen Eiden 	void __user *user_buf_meas = (void __user *)uvio_attest->meas_addr;
1144689752cSSteffen Eiden 	void __user *user_buf_uid = &user_uvio_attest->config_uid;
1154689752cSSteffen Eiden 
1164689752cSSteffen Eiden 	if (copy_to_user(user_buf_meas, measurement, uvio_attest->meas_len))
1174689752cSSteffen Eiden 		return -EFAULT;
1184689752cSSteffen Eiden 	if (add_data && copy_to_user(user_buf_add, add_data, uvio_attest->add_data_len))
1194689752cSSteffen Eiden 		return -EFAULT;
1204689752cSSteffen Eiden 	if (copy_to_user(user_buf_uid, uvcb_attest->config_uid, sizeof(uvcb_attest->config_uid)))
1214689752cSSteffen Eiden 		return -EFAULT;
1224689752cSSteffen Eiden 	return 0;
1234689752cSSteffen Eiden }
1244689752cSSteffen Eiden 
get_uvio_attest(struct uvio_ioctl_cb * uv_ioctl,struct uvio_attest * uvio_attest)1254689752cSSteffen Eiden static int get_uvio_attest(struct uvio_ioctl_cb *uv_ioctl, struct uvio_attest *uvio_attest)
1264689752cSSteffen Eiden {
1274689752cSSteffen Eiden 	u8 __user *user_arg_buf = (u8 __user *)uv_ioctl->argument_addr;
1284689752cSSteffen Eiden 
1294689752cSSteffen Eiden 	if (copy_from_user(uvio_attest, user_arg_buf, sizeof(*uvio_attest)))
1304689752cSSteffen Eiden 		return -EFAULT;
1314689752cSSteffen Eiden 
1324689752cSSteffen Eiden 	if (uvio_attest->arcb_len > UVIO_ATT_ARCB_MAX_LEN)
1334689752cSSteffen Eiden 		return -EINVAL;
1344689752cSSteffen Eiden 	if (uvio_attest->arcb_len == 0)
1354689752cSSteffen Eiden 		return -EINVAL;
1364689752cSSteffen Eiden 	if (uvio_attest->meas_len > UVIO_ATT_MEASUREMENT_MAX_LEN)
1374689752cSSteffen Eiden 		return -EINVAL;
1384689752cSSteffen Eiden 	if (uvio_attest->meas_len == 0)
1394689752cSSteffen Eiden 		return -EINVAL;
1404689752cSSteffen Eiden 	if (uvio_attest->add_data_len > UVIO_ATT_ADDITIONAL_MAX_LEN)
1414689752cSSteffen Eiden 		return -EINVAL;
1424689752cSSteffen Eiden 	if (uvio_attest->reserved136)
1434689752cSSteffen Eiden 		return -EINVAL;
1444689752cSSteffen Eiden 	return 0;
1454689752cSSteffen Eiden }
1464689752cSSteffen Eiden 
1474689752cSSteffen Eiden /**
1484689752cSSteffen Eiden  * uvio_attestation() - Perform a Retrieve Attestation Measurement UVC.
1494689752cSSteffen Eiden  *
1504689752cSSteffen Eiden  * @uv_ioctl: ioctl control block
1514689752cSSteffen Eiden  *
1524689752cSSteffen Eiden  * uvio_attestation() does a Retrieve Attestation Measurement Ultravisor Call.
1534689752cSSteffen Eiden  * It verifies that the given userspace addresses are valid and request sizes
1544689752cSSteffen Eiden  * are sane. Every other check is made by the Ultravisor (UV) and won't result
1554689752cSSteffen Eiden  * in a negative return value. It copies the input to kernelspace, builds the
1564689752cSSteffen Eiden  * request, sends the UV-call, and copies the result to userspace.
1574689752cSSteffen Eiden  *
1584689752cSSteffen Eiden  * The Attestation Request has two input and two outputs.
1594689752cSSteffen Eiden  * ARCB and User Data are inputs for the UV generated by userspace.
1604689752cSSteffen Eiden  * Measurement and Additional Data are outputs for userspace generated by UV.
1614689752cSSteffen Eiden  *
1624689752cSSteffen Eiden  * The Attestation Request Control Block (ARCB) is a cryptographically verified
1634689752cSSteffen Eiden  * and secured request to UV and User Data is some plaintext data which is
1644689752cSSteffen Eiden  * going to be included in the Attestation Measurement calculation.
1654689752cSSteffen Eiden  *
1664689752cSSteffen Eiden  * Measurement is a cryptographic measurement of the callers properties,
1674689752cSSteffen Eiden  * optional data configured by the ARCB and the user data. If specified by the
1684689752cSSteffen Eiden  * ARCB, UV will add some Additional Data to the measurement calculation.
1694689752cSSteffen Eiden  * This Additional Data is then returned as well.
1704689752cSSteffen Eiden  *
1714689752cSSteffen Eiden  * If the Retrieve Attestation Measurement UV facility is not present,
1724689752cSSteffen Eiden  * UV will return invalid command rc. This won't be fenced in the driver
1734689752cSSteffen Eiden  * and does not result in a negative return value.
1744689752cSSteffen Eiden  *
1754689752cSSteffen Eiden  * Context: might sleep
1764689752cSSteffen Eiden  *
1774689752cSSteffen Eiden  * Return: 0 on success or a negative error code on error.
1784689752cSSteffen Eiden  */
uvio_attestation(struct uvio_ioctl_cb * uv_ioctl)1794689752cSSteffen Eiden static int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl)
1804689752cSSteffen Eiden {
1814689752cSSteffen Eiden 	struct uv_cb_attest *uvcb_attest = NULL;
1824689752cSSteffen Eiden 	struct uvio_attest *uvio_attest = NULL;
1834689752cSSteffen Eiden 	u8 *measurement = NULL;
1844689752cSSteffen Eiden 	u8 *add_data = NULL;
1854689752cSSteffen Eiden 	u8 *arcb = NULL;
1864689752cSSteffen Eiden 	int ret;
1874689752cSSteffen Eiden 
1884689752cSSteffen Eiden 	ret = -EINVAL;
1894689752cSSteffen Eiden 	if (uv_ioctl->argument_len != sizeof(*uvio_attest))
1904689752cSSteffen Eiden 		goto out;
1914689752cSSteffen Eiden 
1924689752cSSteffen Eiden 	ret = -ENOMEM;
1934689752cSSteffen Eiden 	uvio_attest = kzalloc(sizeof(*uvio_attest), GFP_KERNEL);
1944689752cSSteffen Eiden 	if (!uvio_attest)
1954689752cSSteffen Eiden 		goto out;
1964689752cSSteffen Eiden 
1974689752cSSteffen Eiden 	ret = get_uvio_attest(uv_ioctl, uvio_attest);
1984689752cSSteffen Eiden 	if (ret)
1994689752cSSteffen Eiden 		goto out;
2004689752cSSteffen Eiden 
2014689752cSSteffen Eiden 	ret = -ENOMEM;
2024689752cSSteffen Eiden 	arcb = kvzalloc(uvio_attest->arcb_len, GFP_KERNEL);
2034689752cSSteffen Eiden 	measurement = kvzalloc(uvio_attest->meas_len, GFP_KERNEL);
2044689752cSSteffen Eiden 	if (!arcb || !measurement)
2054689752cSSteffen Eiden 		goto out;
2064689752cSSteffen Eiden 
2074689752cSSteffen Eiden 	if (uvio_attest->add_data_len) {
2084689752cSSteffen Eiden 		add_data = kvzalloc(uvio_attest->add_data_len, GFP_KERNEL);
2094689752cSSteffen Eiden 		if (!add_data)
2104689752cSSteffen Eiden 			goto out;
2114689752cSSteffen Eiden 	}
2124689752cSSteffen Eiden 
2134689752cSSteffen Eiden 	uvcb_attest = kzalloc(sizeof(*uvcb_attest), GFP_KERNEL);
2144689752cSSteffen Eiden 	if (!uvcb_attest)
2154689752cSSteffen Eiden 		goto out;
2164689752cSSteffen Eiden 
2174689752cSSteffen Eiden 	ret = uvio_build_uvcb_attest(uvcb_attest, arcb,  measurement, add_data, uvio_attest);
2184689752cSSteffen Eiden 	if (ret)
2194689752cSSteffen Eiden 		goto out;
2204689752cSSteffen Eiden 
2214689752cSSteffen Eiden 	uv_call_sched(0, (u64)uvcb_attest);
2224689752cSSteffen Eiden 
2234689752cSSteffen Eiden 	uv_ioctl->uv_rc = uvcb_attest->header.rc;
2244689752cSSteffen Eiden 	uv_ioctl->uv_rrc = uvcb_attest->header.rrc;
2254689752cSSteffen Eiden 
2264689752cSSteffen Eiden 	ret = uvio_copy_attest_result_to_user(uvcb_attest, uv_ioctl, measurement, add_data,
2274689752cSSteffen Eiden 					      uvio_attest);
2284689752cSSteffen Eiden out:
2294689752cSSteffen Eiden 	kvfree(arcb);
2304689752cSSteffen Eiden 	kvfree(measurement);
2314689752cSSteffen Eiden 	kvfree(add_data);
2324689752cSSteffen Eiden 	kfree(uvio_attest);
2334689752cSSteffen Eiden 	kfree(uvcb_attest);
2344689752cSSteffen Eiden 	return ret;
2354689752cSSteffen Eiden }
2364689752cSSteffen Eiden 
23744567ca2SSteffen Eiden /** uvio_add_secret() - perform an Add Secret UVC
23844567ca2SSteffen Eiden  *
23944567ca2SSteffen Eiden  * @uv_ioctl: ioctl control block
24044567ca2SSteffen Eiden  *
24144567ca2SSteffen Eiden  * uvio_add_secret() performs the Add Secret Ultravisor Call.
24244567ca2SSteffen Eiden  *
24344567ca2SSteffen Eiden  * The given userspace argument address and size are verified to be
24444567ca2SSteffen Eiden  * valid but every other check is made by the Ultravisor
24544567ca2SSteffen Eiden  * (UV). Therefore UV errors won't result in a negative return
24644567ca2SSteffen Eiden  * value. The request is then copied to kernelspace, the UV-call is
24744567ca2SSteffen Eiden  * performed and the results are copied back to userspace.
24844567ca2SSteffen Eiden  *
24944567ca2SSteffen Eiden  * The argument has to point to an Add Secret Request Control Block
25044567ca2SSteffen Eiden  * which is an encrypted and cryptographically verified request that
25144567ca2SSteffen Eiden  * inserts a protected guest's secrets into the Ultravisor for later
25244567ca2SSteffen Eiden  * use.
25344567ca2SSteffen Eiden  *
25444567ca2SSteffen Eiden  * If the Add Secret UV facility is not present, UV will return
25544567ca2SSteffen Eiden  * invalid command rc. This won't be fenced in the driver and does not
25644567ca2SSteffen Eiden  * result in a negative return value.
25744567ca2SSteffen Eiden  *
25844567ca2SSteffen Eiden  * Context: might sleep
25944567ca2SSteffen Eiden  *
26044567ca2SSteffen Eiden  * Return: 0 on success or a negative error code on error.
26144567ca2SSteffen Eiden  */
uvio_add_secret(struct uvio_ioctl_cb * uv_ioctl)26244567ca2SSteffen Eiden static int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl)
26344567ca2SSteffen Eiden {
26444567ca2SSteffen Eiden 	void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr;
26544567ca2SSteffen Eiden 	struct uv_cb_guest_addr uvcb = {
26644567ca2SSteffen Eiden 		.header.len = sizeof(uvcb),
26744567ca2SSteffen Eiden 		.header.cmd = UVC_CMD_ADD_SECRET,
26844567ca2SSteffen Eiden 	};
26944567ca2SSteffen Eiden 	void *asrcb = NULL;
27044567ca2SSteffen Eiden 	int ret;
27144567ca2SSteffen Eiden 
27244567ca2SSteffen Eiden 	if (uv_ioctl->argument_len > UVIO_ADD_SECRET_MAX_LEN)
27344567ca2SSteffen Eiden 		return -EINVAL;
27444567ca2SSteffen Eiden 	if (uv_ioctl->argument_len == 0)
27544567ca2SSteffen Eiden 		return -EINVAL;
27644567ca2SSteffen Eiden 
27744567ca2SSteffen Eiden 	asrcb = kvzalloc(uv_ioctl->argument_len, GFP_KERNEL);
27844567ca2SSteffen Eiden 	if (!asrcb)
27944567ca2SSteffen Eiden 		return -ENOMEM;
28044567ca2SSteffen Eiden 
28144567ca2SSteffen Eiden 	ret = -EFAULT;
28244567ca2SSteffen Eiden 	if (copy_from_user(asrcb, user_buf_arg, uv_ioctl->argument_len))
28344567ca2SSteffen Eiden 		goto out;
28444567ca2SSteffen Eiden 
28544567ca2SSteffen Eiden 	ret = 0;
28644567ca2SSteffen Eiden 	uvcb.addr = (u64)asrcb;
28744567ca2SSteffen Eiden 	uv_call_sched(0, (u64)&uvcb);
28844567ca2SSteffen Eiden 	uv_ioctl->uv_rc = uvcb.header.rc;
28944567ca2SSteffen Eiden 	uv_ioctl->uv_rrc = uvcb.header.rrc;
29044567ca2SSteffen Eiden 
29144567ca2SSteffen Eiden out:
29244567ca2SSteffen Eiden 	kvfree(asrcb);
29344567ca2SSteffen Eiden 	return ret;
29444567ca2SSteffen Eiden }
29544567ca2SSteffen Eiden 
296b96b3ce2SSteffen Eiden /** uvio_list_secrets() - perform a List Secret UVC
297b96b3ce2SSteffen Eiden  * @uv_ioctl: ioctl control block
298b96b3ce2SSteffen Eiden  *
299b96b3ce2SSteffen Eiden  * uvio_list_secrets() performs the List Secret Ultravisor Call. It verifies
300b96b3ce2SSteffen Eiden  * that the given userspace argument address is valid and its size is sane.
301b96b3ce2SSteffen Eiden  * Every other check is made by the Ultravisor (UV) and won't result in a
302b96b3ce2SSteffen Eiden  * negative return value. It builds the request, performs the UV-call, and
303b96b3ce2SSteffen Eiden  * copies the result to userspace.
304b96b3ce2SSteffen Eiden  *
305b96b3ce2SSteffen Eiden  * The argument specifies the location for the result of the UV-Call.
306b96b3ce2SSteffen Eiden  *
307b96b3ce2SSteffen Eiden  * If the List Secrets UV facility is not present, UV will return invalid
308b96b3ce2SSteffen Eiden  * command rc. This won't be fenced in the driver and does not result in a
309b96b3ce2SSteffen Eiden  * negative return value.
310b96b3ce2SSteffen Eiden  *
311b96b3ce2SSteffen Eiden  * Context: might sleep
312b96b3ce2SSteffen Eiden  *
313b96b3ce2SSteffen Eiden  * Return: 0 on success or a negative error code on error.
314b96b3ce2SSteffen Eiden  */
uvio_list_secrets(struct uvio_ioctl_cb * uv_ioctl)315b96b3ce2SSteffen Eiden static int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl)
316b96b3ce2SSteffen Eiden {
317b96b3ce2SSteffen Eiden 	void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr;
318b96b3ce2SSteffen Eiden 	struct uv_cb_guest_addr uvcb = {
319b96b3ce2SSteffen Eiden 		.header.len = sizeof(uvcb),
320b96b3ce2SSteffen Eiden 		.header.cmd = UVC_CMD_LIST_SECRETS,
321b96b3ce2SSteffen Eiden 	};
322b96b3ce2SSteffen Eiden 	void *secrets = NULL;
323b96b3ce2SSteffen Eiden 	int ret = 0;
324b96b3ce2SSteffen Eiden 
325b96b3ce2SSteffen Eiden 	if (uv_ioctl->argument_len != UVIO_LIST_SECRETS_LEN)
326b96b3ce2SSteffen Eiden 		return -EINVAL;
327b96b3ce2SSteffen Eiden 
328b96b3ce2SSteffen Eiden 	secrets = kvzalloc(UVIO_LIST_SECRETS_LEN, GFP_KERNEL);
329b96b3ce2SSteffen Eiden 	if (!secrets)
330b96b3ce2SSteffen Eiden 		return -ENOMEM;
331b96b3ce2SSteffen Eiden 
332b96b3ce2SSteffen Eiden 	uvcb.addr = (u64)secrets;
333b96b3ce2SSteffen Eiden 	uv_call_sched(0, (u64)&uvcb);
334b96b3ce2SSteffen Eiden 	uv_ioctl->uv_rc = uvcb.header.rc;
335b96b3ce2SSteffen Eiden 	uv_ioctl->uv_rrc = uvcb.header.rrc;
336b96b3ce2SSteffen Eiden 
337b96b3ce2SSteffen Eiden 	if (copy_to_user(user_buf_arg, secrets, UVIO_LIST_SECRETS_LEN))
338b96b3ce2SSteffen Eiden 		ret = -EFAULT;
339b96b3ce2SSteffen Eiden 
340b96b3ce2SSteffen Eiden 	kvfree(secrets);
341b96b3ce2SSteffen Eiden 	return ret;
342b96b3ce2SSteffen Eiden }
343b96b3ce2SSteffen Eiden 
344*2d8a26acSSteffen Eiden /** uvio_lock_secrets() - perform a Lock Secret Store UVC
345*2d8a26acSSteffen Eiden  * @uv_ioctl: ioctl control block
346*2d8a26acSSteffen Eiden  *
347*2d8a26acSSteffen Eiden  * uvio_lock_secrets() performs the Lock Secret Store Ultravisor Call. It
348*2d8a26acSSteffen Eiden  * performs the UV-call and copies the return codes to the ioctl control block.
349*2d8a26acSSteffen Eiden  * After this call was dispatched successfully every following Add Secret UVC
350*2d8a26acSSteffen Eiden  * and Lock Secrets UVC will fail with return code 0x102.
351*2d8a26acSSteffen Eiden  *
352*2d8a26acSSteffen Eiden  * The argument address and size must be 0.
353*2d8a26acSSteffen Eiden  *
354*2d8a26acSSteffen Eiden  * If the Lock Secrets UV facility is not present, UV will return invalid
355*2d8a26acSSteffen Eiden  * command rc. This won't be fenced in the driver and does not result in a
356*2d8a26acSSteffen Eiden  * negative return value.
357*2d8a26acSSteffen Eiden  *
358*2d8a26acSSteffen Eiden  * Context: might sleep
359*2d8a26acSSteffen Eiden  *
360*2d8a26acSSteffen Eiden  * Return: 0 on success or a negative error code on error.
361*2d8a26acSSteffen Eiden  */
uvio_lock_secrets(struct uvio_ioctl_cb * ioctl)362*2d8a26acSSteffen Eiden static int uvio_lock_secrets(struct uvio_ioctl_cb *ioctl)
363*2d8a26acSSteffen Eiden {
364*2d8a26acSSteffen Eiden 	struct uv_cb_nodata uvcb = {
365*2d8a26acSSteffen Eiden 		.header.len = sizeof(uvcb),
366*2d8a26acSSteffen Eiden 		.header.cmd = UVC_CMD_LOCK_SECRETS,
367*2d8a26acSSteffen Eiden 	};
368*2d8a26acSSteffen Eiden 
369*2d8a26acSSteffen Eiden 	if (ioctl->argument_addr || ioctl->argument_len)
370*2d8a26acSSteffen Eiden 		return -EINVAL;
371*2d8a26acSSteffen Eiden 
372*2d8a26acSSteffen Eiden 	uv_call(0, (u64)&uvcb);
373*2d8a26acSSteffen Eiden 	ioctl->uv_rc = uvcb.header.rc;
374*2d8a26acSSteffen Eiden 	ioctl->uv_rrc = uvcb.header.rrc;
375*2d8a26acSSteffen Eiden 
376*2d8a26acSSteffen Eiden 	return 0;
377*2d8a26acSSteffen Eiden }
378*2d8a26acSSteffen Eiden 
uvio_copy_and_check_ioctl(struct uvio_ioctl_cb * ioctl,void __user * argp,unsigned long cmd)379ea9d9716SSteffen Eiden static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp,
380ea9d9716SSteffen Eiden 				     unsigned long cmd)
3814689752cSSteffen Eiden {
382ea9d9716SSteffen Eiden 	u8 nr = _IOC_NR(cmd);
383ea9d9716SSteffen Eiden 
384ea9d9716SSteffen Eiden 	if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
385ea9d9716SSteffen Eiden 		return -ENOIOCTLCMD;
386ea9d9716SSteffen Eiden 	if (_IOC_TYPE(cmd) != UVIO_TYPE_UVC)
387ea9d9716SSteffen Eiden 		return -ENOIOCTLCMD;
388ea9d9716SSteffen Eiden 	if (nr >= UVIO_IOCTL_NUM_IOCTLS)
389ea9d9716SSteffen Eiden 		return -ENOIOCTLCMD;
390ea9d9716SSteffen Eiden 	if (_IOC_SIZE(cmd) != sizeof(*ioctl))
391ea9d9716SSteffen Eiden 		return -ENOIOCTLCMD;
3924689752cSSteffen Eiden 	if (copy_from_user(ioctl, argp, sizeof(*ioctl)))
3934689752cSSteffen Eiden 		return -EFAULT;
3944689752cSSteffen Eiden 	if (ioctl->flags != 0)
3954689752cSSteffen Eiden 		return -EINVAL;
3964689752cSSteffen Eiden 	if (memchr_inv(ioctl->reserved14, 0, sizeof(ioctl->reserved14)))
3974689752cSSteffen Eiden 		return -EINVAL;
3984689752cSSteffen Eiden 
399ea9d9716SSteffen Eiden 	return nr;
4004689752cSSteffen Eiden }
4014689752cSSteffen Eiden 
4024689752cSSteffen Eiden /*
4034689752cSSteffen Eiden  * IOCTL entry point for the Ultravisor device.
4044689752cSSteffen Eiden  */
uvio_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)4054689752cSSteffen Eiden static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4064689752cSSteffen Eiden {
4074689752cSSteffen Eiden 	void __user *argp = (void __user *)arg;
4084689752cSSteffen Eiden 	struct uvio_ioctl_cb uv_ioctl = { };
4094689752cSSteffen Eiden 	long ret;
410ea9d9716SSteffen Eiden 	int nr;
4114689752cSSteffen Eiden 
412ea9d9716SSteffen Eiden 	nr = uvio_copy_and_check_ioctl(&uv_ioctl, argp, cmd);
413ea9d9716SSteffen Eiden 	if (nr < 0)
414ea9d9716SSteffen Eiden 		return nr;
415ea9d9716SSteffen Eiden 
416ea9d9716SSteffen Eiden 	switch (nr) {
417ea9d9716SSteffen Eiden 	case UVIO_IOCTL_UVDEV_INFO_NR:
418ea9d9716SSteffen Eiden 		ret = uvio_uvdev_info(&uv_ioctl);
419ea9d9716SSteffen Eiden 		break;
420ea9d9716SSteffen Eiden 	case UVIO_IOCTL_ATT_NR:
4214689752cSSteffen Eiden 		ret = uvio_attestation(&uv_ioctl);
4224689752cSSteffen Eiden 		break;
42344567ca2SSteffen Eiden 	case UVIO_IOCTL_ADD_SECRET_NR:
42444567ca2SSteffen Eiden 		ret = uvio_add_secret(&uv_ioctl);
42544567ca2SSteffen Eiden 		break;
426b96b3ce2SSteffen Eiden 	case UVIO_IOCTL_LIST_SECRETS_NR:
427b96b3ce2SSteffen Eiden 		ret = uvio_list_secrets(&uv_ioctl);
428b96b3ce2SSteffen Eiden 		break;
429*2d8a26acSSteffen Eiden 	case UVIO_IOCTL_LOCK_SECRETS_NR:
430*2d8a26acSSteffen Eiden 		ret = uvio_lock_secrets(&uv_ioctl);
431*2d8a26acSSteffen Eiden 		break;
4324689752cSSteffen Eiden 	default:
4334689752cSSteffen Eiden 		ret = -ENOIOCTLCMD;
4344689752cSSteffen Eiden 		break;
4354689752cSSteffen Eiden 	}
4364689752cSSteffen Eiden 	if (ret)
4374689752cSSteffen Eiden 		return ret;
4384689752cSSteffen Eiden 
4394689752cSSteffen Eiden 	if (copy_to_user(argp, &uv_ioctl, sizeof(uv_ioctl)))
4404689752cSSteffen Eiden 		ret = -EFAULT;
4414689752cSSteffen Eiden 
4424689752cSSteffen Eiden 	return ret;
4434689752cSSteffen Eiden }
4444689752cSSteffen Eiden 
4454689752cSSteffen Eiden static const struct file_operations uvio_dev_fops = {
4464689752cSSteffen Eiden 	.owner = THIS_MODULE,
4474689752cSSteffen Eiden 	.unlocked_ioctl = uvio_ioctl,
4484689752cSSteffen Eiden 	.llseek = no_llseek,
4494689752cSSteffen Eiden };
4504689752cSSteffen Eiden 
4514689752cSSteffen Eiden static struct miscdevice uvio_dev_miscdev = {
4524689752cSSteffen Eiden 	.minor = MISC_DYNAMIC_MINOR,
4534689752cSSteffen Eiden 	.name = UVIO_DEVICE_NAME,
4544689752cSSteffen Eiden 	.fops = &uvio_dev_fops,
4554689752cSSteffen Eiden };
4564689752cSSteffen Eiden 
uvio_dev_exit(void)4574689752cSSteffen Eiden static void __exit uvio_dev_exit(void)
4584689752cSSteffen Eiden {
4594689752cSSteffen Eiden 	misc_deregister(&uvio_dev_miscdev);
4604689752cSSteffen Eiden }
4614689752cSSteffen Eiden 
uvio_dev_init(void)4624689752cSSteffen Eiden static int __init uvio_dev_init(void)
4634689752cSSteffen Eiden {
464ea9d9716SSteffen Eiden 	set_supp_uv_cmds((unsigned long *)&uvdev_info.supp_uv_cmds);
4654689752cSSteffen Eiden 	return misc_register(&uvio_dev_miscdev);
4664689752cSSteffen Eiden }
4674689752cSSteffen Eiden 
4685fcd0d8aSSteffen Eiden module_cpu_feature_match(S390_CPU_FEATURE_UV, uvio_dev_init);
4694689752cSSteffen Eiden module_exit(uvio_dev_exit);
4704689752cSSteffen Eiden 
4714689752cSSteffen Eiden MODULE_AUTHOR("IBM Corporation");
4724689752cSSteffen Eiden MODULE_LICENSE("GPL");
4734689752cSSteffen Eiden MODULE_DESCRIPTION("Ultravisor UAPI driver");
474