Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Steffen Eiden and committed by
Janosch Frank
ea9d9716 4255ce01

+112 -9
+41 -1
arch/s390/include/uapi/asm/uvdevice.h
··· 32 32 __u16 reserved136; /* 0x0136 */ 33 33 }; 34 34 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 + 35 62 /* 36 63 * The following max values define an upper length for the IOCTL in/out buffers. 37 64 * However, they do not represent the maximum the Ultravisor allows which is ··· 73 46 #define UVIO_DEVICE_NAME "uv" 74 47 #define UVIO_TYPE_UVC 'u' 75 48 76 - #define UVIO_IOCTL_ATT _IOWR(UVIO_TYPE_UVC, 0x01, struct uvio_ioctl_cb) 49 + enum UVIO_IOCTL_NR { 50 + UVIO_IOCTL_UVDEV_INFO_NR = 0x00, 51 + UVIO_IOCTL_ATT_NR, 52 + /* must be the last entry */ 53 + UVIO_IOCTL_NUM_IOCTLS 54 + }; 55 + 56 + #define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb) 57 + #define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR) 58 + #define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) 59 + 60 + #define UVIO_SUPP_CALL(nr) (1ULL << (nr)) 61 + #define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) 62 + #define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) 77 63 78 64 #endif /* __S390_ASM_UVDEVICE_H */
+1 -1
drivers/s390/char/Kconfig
··· 96 96 config S390_UV_UAPI 97 97 def_tristate m 98 98 prompt "Ultravisor userspace API" 99 - depends on S390 99 + depends on S390 && (KVM || PROTECTED_VIRTUALIZATION_GUEST) 100 100 help 101 101 Selecting exposes parts of the UV interface to userspace 102 102 by providing a misc character device at /dev/uv.
+70 -7
drivers/s390/char/uvdevice.c
··· 32 32 #include <asm/uvdevice.h> 33 33 #include <asm/uv.h> 34 34 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 + 35 81 static int uvio_build_uvcb_attest(struct uv_cb_attest *uvcb_attest, u8 *arcb, 36 82 u8 *meas, u8 *add_data, struct uvio_attest *uvio_attest) 37 83 { ··· 231 185 return ret; 232 186 } 233 187 234 - static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp) 188 + static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, 189 + unsigned long cmd) 235 190 { 191 + u8 nr = _IOC_NR(cmd); 192 + 193 + if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) 194 + return -ENOIOCTLCMD; 195 + if (_IOC_TYPE(cmd) != UVIO_TYPE_UVC) 196 + return -ENOIOCTLCMD; 197 + if (nr >= UVIO_IOCTL_NUM_IOCTLS) 198 + return -ENOIOCTLCMD; 199 + if (_IOC_SIZE(cmd) != sizeof(*ioctl)) 200 + return -ENOIOCTLCMD; 236 201 if (copy_from_user(ioctl, argp, sizeof(*ioctl))) 237 202 return -EFAULT; 238 203 if (ioctl->flags != 0) ··· 251 194 if (memchr_inv(ioctl->reserved14, 0, sizeof(ioctl->reserved14))) 252 195 return -EINVAL; 253 196 254 - return 0; 197 + return nr; 255 198 } 256 199 257 200 /* ··· 262 205 void __user *argp = (void __user *)arg; 263 206 struct uvio_ioctl_cb uv_ioctl = { }; 264 207 long ret; 208 + int nr; 265 209 266 - switch (cmd) { 267 - case UVIO_IOCTL_ATT: 268 - ret = uvio_copy_and_check_ioctl(&uv_ioctl, argp); 269 - if (ret) 270 - return ret; 210 + nr = uvio_copy_and_check_ioctl(&uv_ioctl, argp, cmd); 211 + if (nr < 0) 212 + return nr; 213 + 214 + switch (nr) { 215 + case UVIO_IOCTL_UVDEV_INFO_NR: 216 + ret = uvio_uvdev_info(&uv_ioctl); 217 + break; 218 + case UVIO_IOCTL_ATT_NR: 271 219 ret = uvio_attestation(&uv_ioctl); 272 220 break; 273 221 default: ··· 307 245 308 246 static int __init uvio_dev_init(void) 309 247 { 248 + set_supp_uv_cmds((unsigned long *)&uvdev_info.supp_uv_cmds); 310 249 return misc_register(&uvio_dev_miscdev); 311 250 } 312 251