Skip to content

Commit ea9d971

Browse files
steffen-eidenfrankjaa
authored andcommitted
s390/uvdevice: Add info IOCTL
Add an IOCTL that allows userspace to find out which IOCTLs the uvdevice supports without trial and error. Explicitly expose the IOCTL nr for the request types. Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> Reviewed-by: Janosch Frank <frankja@linux.ibm.com> Link: https://lore.kernel.org/r/20230615100533.3996107-3-seiden@linux.ibm.com Signed-off-by: Janosch Frank <frankja@linux.ibm.com> Message-Id: <20230615100533.3996107-3-seiden@linux.ibm.com>
1 parent 4255ce0 commit ea9d971

3 files changed

Lines changed: 112 additions & 9 deletions

File tree

arch/s390/include/uapi/asm/uvdevice.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,33 @@ struct uvio_attest {
3232
__u16 reserved136; /* 0x0136 */
3333
};
3434

35+
/**
36+
* uvio_uvdev_info - Information of supported functions
37+
* @supp_uvio_cmds - supported IOCTLs by this device
38+
* @supp_uv_cmds - supported UVCs corresponding to the IOCTL
39+
*
40+
* UVIO request to get information about supported request types by this
41+
* uvdevice and the Ultravisor. Everything is output. Bits are in LSB0
42+
* ordering. If the bit is set in both, @supp_uvio_cmds and @supp_uv_cmds, the
43+
* uvdevice and the Ultravisor support that call.
44+
*
45+
* Note that bit 0 (UVIO_IOCTL_UVDEV_INFO_NR) is always zero for `supp_uv_cmds`
46+
* as there is no corresponding UV-call.
47+
*/
48+
struct uvio_uvdev_info {
49+
/*
50+
* If bit `n` is set, this device supports the IOCTL with nr `n`.
51+
*/
52+
__u64 supp_uvio_cmds;
53+
/*
54+
* If bit `n` is set, the Ultravisor(UV) supports the UV-call
55+
* corresponding to the IOCTL with nr `n` in the calling contextx (host
56+
* or guest). The value is only valid if the corresponding bit in
57+
* @supp_uvio_cmds is set as well.
58+
*/
59+
__u64 supp_uv_cmds;
60+
};
61+
3562
/*
3663
* The following max values define an upper length for the IOCTL in/out buffers.
3764
* However, they do not represent the maximum the Ultravisor allows which is
@@ -46,6 +73,19 @@ struct uvio_attest {
4673
#define UVIO_DEVICE_NAME "uv"
4774
#define UVIO_TYPE_UVC 'u'
4875

49-
#define UVIO_IOCTL_ATT _IOWR(UVIO_TYPE_UVC, 0x01, struct uvio_ioctl_cb)
76+
enum UVIO_IOCTL_NR {
77+
UVIO_IOCTL_UVDEV_INFO_NR = 0x00,
78+
UVIO_IOCTL_ATT_NR,
79+
/* must be the last entry */
80+
UVIO_IOCTL_NUM_IOCTLS
81+
};
82+
83+
#define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb)
84+
#define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR)
85+
#define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR)
86+
87+
#define UVIO_SUPP_CALL(nr) (1ULL << (nr))
88+
#define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR)
89+
#define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR)
5090

5191
#endif /* __S390_ASM_UVDEVICE_H */

drivers/s390/char/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ config SCLP_OFB
9696
config S390_UV_UAPI
9797
def_tristate m
9898
prompt "Ultravisor userspace API"
99-
depends on S390
99+
depends on S390 && (KVM || PROTECTED_VIRTUALIZATION_GUEST)
100100
help
101101
Selecting exposes parts of the UV interface to userspace
102102
by providing a misc character device at /dev/uv.

drivers/s390/char/uvdevice.c

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,52 @@
3232
#include <asm/uvdevice.h>
3333
#include <asm/uv.h>
3434

35+
#define BIT_UVIO_INTERNAL U32_MAX
36+
/* Mapping from IOCTL-nr to UVC-bit */
37+
static const u32 ioctl_nr_to_uvc_bit[] __initconst = {
38+
[UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL,
39+
[UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST,
40+
};
41+
42+
static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS);
43+
44+
static struct uvio_uvdev_info uvdev_info = {
45+
.supp_uvio_cmds = GENMASK_ULL(UVIO_IOCTL_NUM_IOCTLS - 1, 0),
46+
};
47+
48+
static void __init set_supp_uv_cmds(unsigned long *supp_uv_cmds)
49+
{
50+
int i;
51+
52+
for (i = 0; i < UVIO_IOCTL_NUM_IOCTLS; i++) {
53+
if (ioctl_nr_to_uvc_bit[i] == BIT_UVIO_INTERNAL)
54+
continue;
55+
if (!test_bit_inv(ioctl_nr_to_uvc_bit[i], uv_info.inst_calls_list))
56+
continue;
57+
__set_bit(i, supp_uv_cmds);
58+
}
59+
}
60+
61+
/**
62+
* uvio_uvdev_info() - get information about the uvdevice
63+
*
64+
* @uv_ioctl: ioctl control block
65+
*
66+
* Lists all IOCTLs that are supported by this uvdevice
67+
*/
68+
static int uvio_uvdev_info(struct uvio_ioctl_cb *uv_ioctl)
69+
{
70+
void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr;
71+
72+
if (uv_ioctl->argument_len < sizeof(uvdev_info))
73+
return -EINVAL;
74+
if (copy_to_user(user_buf_arg, &uvdev_info, sizeof(uvdev_info)))
75+
return -EFAULT;
76+
77+
uv_ioctl->uv_rc = UVC_RC_EXECUTED;
78+
return 0;
79+
}
80+
3581
static int uvio_build_uvcb_attest(struct uv_cb_attest *uvcb_attest, u8 *arcb,
3682
u8 *meas, u8 *add_data, struct uvio_attest *uvio_attest)
3783
{
@@ -185,16 +231,27 @@ static int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl)
185231
return ret;
186232
}
187233

188-
static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp)
234+
static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp,
235+
unsigned long cmd)
189236
{
237+
u8 nr = _IOC_NR(cmd);
238+
239+
if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
240+
return -ENOIOCTLCMD;
241+
if (_IOC_TYPE(cmd) != UVIO_TYPE_UVC)
242+
return -ENOIOCTLCMD;
243+
if (nr >= UVIO_IOCTL_NUM_IOCTLS)
244+
return -ENOIOCTLCMD;
245+
if (_IOC_SIZE(cmd) != sizeof(*ioctl))
246+
return -ENOIOCTLCMD;
190247
if (copy_from_user(ioctl, argp, sizeof(*ioctl)))
191248
return -EFAULT;
192249
if (ioctl->flags != 0)
193250
return -EINVAL;
194251
if (memchr_inv(ioctl->reserved14, 0, sizeof(ioctl->reserved14)))
195252
return -EINVAL;
196253

197-
return 0;
254+
return nr;
198255
}
199256

200257
/*
@@ -205,12 +262,17 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
205262
void __user *argp = (void __user *)arg;
206263
struct uvio_ioctl_cb uv_ioctl = { };
207264
long ret;
265+
int nr;
266+
267+
nr = uvio_copy_and_check_ioctl(&uv_ioctl, argp, cmd);
268+
if (nr < 0)
269+
return nr;
208270

209-
switch (cmd) {
210-
case UVIO_IOCTL_ATT:
211-
ret = uvio_copy_and_check_ioctl(&uv_ioctl, argp);
212-
if (ret)
213-
return ret;
271+
switch (nr) {
272+
case UVIO_IOCTL_UVDEV_INFO_NR:
273+
ret = uvio_uvdev_info(&uv_ioctl);
274+
break;
275+
case UVIO_IOCTL_ATT_NR:
214276
ret = uvio_attestation(&uv_ioctl);
215277
break;
216278
default:
@@ -245,6 +307,7 @@ static void __exit uvio_dev_exit(void)
245307

246308
static int __init uvio_dev_init(void)
247309
{
310+
set_supp_uv_cmds((unsigned long *)&uvdev_info.supp_uv_cmds);
248311
return misc_register(&uvio_dev_miscdev);
249312
}
250313

0 commit comments

Comments
 (0)