1*ff6301daSIvan Hu /* 2*ff6301daSIvan Hu * EFI Test Driver for Runtime Services 3*ff6301daSIvan Hu * 4*ff6301daSIvan Hu * Copyright(C) 2012-2016 Canonical Ltd. 5*ff6301daSIvan Hu * 6*ff6301daSIvan Hu * This driver exports EFI runtime services interfaces into userspace, which 7*ff6301daSIvan Hu * allow to use and test UEFI runtime services provided by firmware. 8*ff6301daSIvan Hu * 9*ff6301daSIvan Hu */ 10*ff6301daSIvan Hu 11*ff6301daSIvan Hu #include <linux/version.h> 12*ff6301daSIvan Hu #include <linux/miscdevice.h> 13*ff6301daSIvan Hu #include <linux/module.h> 14*ff6301daSIvan Hu #include <linux/init.h> 15*ff6301daSIvan Hu #include <linux/proc_fs.h> 16*ff6301daSIvan Hu #include <linux/efi.h> 17*ff6301daSIvan Hu #include <linux/slab.h> 18*ff6301daSIvan Hu #include <linux/uaccess.h> 19*ff6301daSIvan Hu 20*ff6301daSIvan Hu #include "efi_test.h" 21*ff6301daSIvan Hu 22*ff6301daSIvan Hu MODULE_AUTHOR("Ivan Hu <ivan.hu@canonical.com>"); 23*ff6301daSIvan Hu MODULE_DESCRIPTION("EFI Test Driver"); 24*ff6301daSIvan Hu MODULE_LICENSE("GPL"); 25*ff6301daSIvan Hu 26*ff6301daSIvan Hu /* 27*ff6301daSIvan Hu * Count the bytes in 'str', including the terminating NULL. 28*ff6301daSIvan Hu * 29*ff6301daSIvan Hu * Note this function returns the number of *bytes*, not the number of 30*ff6301daSIvan Hu * ucs2 characters. 31*ff6301daSIvan Hu */ 32*ff6301daSIvan Hu static inline size_t user_ucs2_strsize(efi_char16_t __user *str) 33*ff6301daSIvan Hu { 34*ff6301daSIvan Hu efi_char16_t *s = str, c; 35*ff6301daSIvan Hu size_t len; 36*ff6301daSIvan Hu 37*ff6301daSIvan Hu if (!str) 38*ff6301daSIvan Hu return 0; 39*ff6301daSIvan Hu 40*ff6301daSIvan Hu /* Include terminating NULL */ 41*ff6301daSIvan Hu len = sizeof(efi_char16_t); 42*ff6301daSIvan Hu 43*ff6301daSIvan Hu if (get_user(c, s++)) { 44*ff6301daSIvan Hu /* Can't read userspace memory for size */ 45*ff6301daSIvan Hu return 0; 46*ff6301daSIvan Hu } 47*ff6301daSIvan Hu 48*ff6301daSIvan Hu while (c != 0) { 49*ff6301daSIvan Hu if (get_user(c, s++)) { 50*ff6301daSIvan Hu /* Can't read userspace memory for size */ 51*ff6301daSIvan Hu return 0; 52*ff6301daSIvan Hu } 53*ff6301daSIvan Hu len += sizeof(efi_char16_t); 54*ff6301daSIvan Hu } 55*ff6301daSIvan Hu return len; 56*ff6301daSIvan Hu } 57*ff6301daSIvan Hu 58*ff6301daSIvan Hu /* 59*ff6301daSIvan Hu * Allocate a buffer and copy a ucs2 string from user space into it. 60*ff6301daSIvan Hu */ 61*ff6301daSIvan Hu static inline int 62*ff6301daSIvan Hu copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src, 63*ff6301daSIvan Hu size_t len) 64*ff6301daSIvan Hu { 65*ff6301daSIvan Hu efi_char16_t *buf; 66*ff6301daSIvan Hu 67*ff6301daSIvan Hu if (!src) { 68*ff6301daSIvan Hu *dst = NULL; 69*ff6301daSIvan Hu return 0; 70*ff6301daSIvan Hu } 71*ff6301daSIvan Hu 72*ff6301daSIvan Hu if (!access_ok(VERIFY_READ, src, 1)) 73*ff6301daSIvan Hu return -EFAULT; 74*ff6301daSIvan Hu 75*ff6301daSIvan Hu buf = kmalloc(len, GFP_KERNEL); 76*ff6301daSIvan Hu if (!buf) { 77*ff6301daSIvan Hu *dst = NULL; 78*ff6301daSIvan Hu return -ENOMEM; 79*ff6301daSIvan Hu } 80*ff6301daSIvan Hu *dst = buf; 81*ff6301daSIvan Hu 82*ff6301daSIvan Hu if (copy_from_user(*dst, src, len)) { 83*ff6301daSIvan Hu kfree(buf); 84*ff6301daSIvan Hu return -EFAULT; 85*ff6301daSIvan Hu } 86*ff6301daSIvan Hu 87*ff6301daSIvan Hu return 0; 88*ff6301daSIvan Hu } 89*ff6301daSIvan Hu 90*ff6301daSIvan Hu /* 91*ff6301daSIvan Hu * Count the bytes in 'str', including the terminating NULL. 92*ff6301daSIvan Hu * 93*ff6301daSIvan Hu * Just a wrap for user_ucs2_strsize 94*ff6301daSIvan Hu */ 95*ff6301daSIvan Hu static inline int 96*ff6301daSIvan Hu get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len) 97*ff6301daSIvan Hu { 98*ff6301daSIvan Hu if (!access_ok(VERIFY_READ, src, 1)) 99*ff6301daSIvan Hu return -EFAULT; 100*ff6301daSIvan Hu 101*ff6301daSIvan Hu *len = user_ucs2_strsize(src); 102*ff6301daSIvan Hu if (*len == 0) 103*ff6301daSIvan Hu return -EFAULT; 104*ff6301daSIvan Hu 105*ff6301daSIvan Hu return 0; 106*ff6301daSIvan Hu } 107*ff6301daSIvan Hu 108*ff6301daSIvan Hu /* 109*ff6301daSIvan Hu * Calculate the required buffer allocation size and copy a ucs2 string 110*ff6301daSIvan Hu * from user space into it. 111*ff6301daSIvan Hu * 112*ff6301daSIvan Hu * This function differs from copy_ucs2_from_user_len() because it 113*ff6301daSIvan Hu * calculates the size of the buffer to allocate by taking the length of 114*ff6301daSIvan Hu * the string 'src'. 115*ff6301daSIvan Hu * 116*ff6301daSIvan Hu * If a non-zero value is returned, the caller MUST NOT access 'dst'. 117*ff6301daSIvan Hu * 118*ff6301daSIvan Hu * It is the caller's responsibility to free 'dst'. 119*ff6301daSIvan Hu */ 120*ff6301daSIvan Hu static inline int 121*ff6301daSIvan Hu copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src) 122*ff6301daSIvan Hu { 123*ff6301daSIvan Hu size_t len; 124*ff6301daSIvan Hu 125*ff6301daSIvan Hu if (!access_ok(VERIFY_READ, src, 1)) 126*ff6301daSIvan Hu return -EFAULT; 127*ff6301daSIvan Hu 128*ff6301daSIvan Hu len = user_ucs2_strsize(src); 129*ff6301daSIvan Hu if (len == 0) 130*ff6301daSIvan Hu return -EFAULT; 131*ff6301daSIvan Hu return copy_ucs2_from_user_len(dst, src, len); 132*ff6301daSIvan Hu } 133*ff6301daSIvan Hu 134*ff6301daSIvan Hu /* 135*ff6301daSIvan Hu * Copy a ucs2 string to a user buffer. 136*ff6301daSIvan Hu * 137*ff6301daSIvan Hu * This function is a simple wrapper around copy_to_user() that does 138*ff6301daSIvan Hu * nothing if 'src' is NULL, which is useful for reducing the amount of 139*ff6301daSIvan Hu * NULL checking the caller has to do. 140*ff6301daSIvan Hu * 141*ff6301daSIvan Hu * 'len' specifies the number of bytes to copy. 142*ff6301daSIvan Hu */ 143*ff6301daSIvan Hu static inline int 144*ff6301daSIvan Hu copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len) 145*ff6301daSIvan Hu { 146*ff6301daSIvan Hu if (!src) 147*ff6301daSIvan Hu return 0; 148*ff6301daSIvan Hu 149*ff6301daSIvan Hu if (!access_ok(VERIFY_WRITE, dst, 1)) 150*ff6301daSIvan Hu return -EFAULT; 151*ff6301daSIvan Hu 152*ff6301daSIvan Hu return copy_to_user(dst, src, len); 153*ff6301daSIvan Hu } 154*ff6301daSIvan Hu 155*ff6301daSIvan Hu static long efi_runtime_get_variable(unsigned long arg) 156*ff6301daSIvan Hu { 157*ff6301daSIvan Hu struct efi_getvariable __user *getvariable_user; 158*ff6301daSIvan Hu struct efi_getvariable getvariable; 159*ff6301daSIvan Hu unsigned long datasize, prev_datasize, *dz; 160*ff6301daSIvan Hu efi_guid_t vendor_guid, *vd = NULL; 161*ff6301daSIvan Hu efi_status_t status; 162*ff6301daSIvan Hu efi_char16_t *name = NULL; 163*ff6301daSIvan Hu u32 attr, *at; 164*ff6301daSIvan Hu void *data = NULL; 165*ff6301daSIvan Hu int rv = 0; 166*ff6301daSIvan Hu 167*ff6301daSIvan Hu getvariable_user = (struct efi_getvariable __user *)arg; 168*ff6301daSIvan Hu 169*ff6301daSIvan Hu if (copy_from_user(&getvariable, getvariable_user, 170*ff6301daSIvan Hu sizeof(getvariable))) 171*ff6301daSIvan Hu return -EFAULT; 172*ff6301daSIvan Hu if (getvariable.data_size && 173*ff6301daSIvan Hu get_user(datasize, getvariable.data_size)) 174*ff6301daSIvan Hu return -EFAULT; 175*ff6301daSIvan Hu if (getvariable.vendor_guid) { 176*ff6301daSIvan Hu if (copy_from_user(&vendor_guid, getvariable.vendor_guid, 177*ff6301daSIvan Hu sizeof(vendor_guid))) 178*ff6301daSIvan Hu return -EFAULT; 179*ff6301daSIvan Hu vd = &vendor_guid; 180*ff6301daSIvan Hu } 181*ff6301daSIvan Hu 182*ff6301daSIvan Hu if (getvariable.variable_name) { 183*ff6301daSIvan Hu rv = copy_ucs2_from_user(&name, getvariable.variable_name); 184*ff6301daSIvan Hu if (rv) 185*ff6301daSIvan Hu return rv; 186*ff6301daSIvan Hu } 187*ff6301daSIvan Hu 188*ff6301daSIvan Hu at = getvariable.attributes ? &attr : NULL; 189*ff6301daSIvan Hu dz = getvariable.data_size ? &datasize : NULL; 190*ff6301daSIvan Hu 191*ff6301daSIvan Hu if (getvariable.data_size && getvariable.data) { 192*ff6301daSIvan Hu data = kmalloc(datasize, GFP_KERNEL); 193*ff6301daSIvan Hu if (!data) { 194*ff6301daSIvan Hu kfree(name); 195*ff6301daSIvan Hu return -ENOMEM; 196*ff6301daSIvan Hu } 197*ff6301daSIvan Hu } 198*ff6301daSIvan Hu 199*ff6301daSIvan Hu prev_datasize = datasize; 200*ff6301daSIvan Hu status = efi.get_variable(name, vd, at, dz, data); 201*ff6301daSIvan Hu kfree(name); 202*ff6301daSIvan Hu 203*ff6301daSIvan Hu if (put_user(status, getvariable.status)) { 204*ff6301daSIvan Hu rv = -EFAULT; 205*ff6301daSIvan Hu goto out; 206*ff6301daSIvan Hu } 207*ff6301daSIvan Hu 208*ff6301daSIvan Hu if (status != EFI_SUCCESS) { 209*ff6301daSIvan Hu if (status == EFI_BUFFER_TOO_SMALL) { 210*ff6301daSIvan Hu if (dz && put_user(datasize, getvariable.data_size)) { 211*ff6301daSIvan Hu rv = -EFAULT; 212*ff6301daSIvan Hu goto out; 213*ff6301daSIvan Hu } 214*ff6301daSIvan Hu } 215*ff6301daSIvan Hu rv = -EINVAL; 216*ff6301daSIvan Hu goto out; 217*ff6301daSIvan Hu } 218*ff6301daSIvan Hu 219*ff6301daSIvan Hu if (prev_datasize < datasize) { 220*ff6301daSIvan Hu rv = -EINVAL; 221*ff6301daSIvan Hu goto out; 222*ff6301daSIvan Hu } 223*ff6301daSIvan Hu 224*ff6301daSIvan Hu if (data) { 225*ff6301daSIvan Hu if (copy_to_user(getvariable.data, data, datasize)) { 226*ff6301daSIvan Hu rv = -EFAULT; 227*ff6301daSIvan Hu goto out; 228*ff6301daSIvan Hu } 229*ff6301daSIvan Hu } 230*ff6301daSIvan Hu 231*ff6301daSIvan Hu if (at && put_user(attr, getvariable.attributes)) { 232*ff6301daSIvan Hu rv = -EFAULT; 233*ff6301daSIvan Hu goto out; 234*ff6301daSIvan Hu } 235*ff6301daSIvan Hu 236*ff6301daSIvan Hu if (dz && put_user(datasize, getvariable.data_size)) 237*ff6301daSIvan Hu rv = -EFAULT; 238*ff6301daSIvan Hu 239*ff6301daSIvan Hu out: 240*ff6301daSIvan Hu kfree(data); 241*ff6301daSIvan Hu return rv; 242*ff6301daSIvan Hu 243*ff6301daSIvan Hu } 244*ff6301daSIvan Hu 245*ff6301daSIvan Hu static long efi_runtime_set_variable(unsigned long arg) 246*ff6301daSIvan Hu { 247*ff6301daSIvan Hu struct efi_setvariable __user *setvariable_user; 248*ff6301daSIvan Hu struct efi_setvariable setvariable; 249*ff6301daSIvan Hu efi_guid_t vendor_guid; 250*ff6301daSIvan Hu efi_status_t status; 251*ff6301daSIvan Hu efi_char16_t *name = NULL; 252*ff6301daSIvan Hu void *data; 253*ff6301daSIvan Hu int rv = 0; 254*ff6301daSIvan Hu 255*ff6301daSIvan Hu setvariable_user = (struct efi_setvariable __user *)arg; 256*ff6301daSIvan Hu 257*ff6301daSIvan Hu if (copy_from_user(&setvariable, setvariable_user, sizeof(setvariable))) 258*ff6301daSIvan Hu return -EFAULT; 259*ff6301daSIvan Hu if (copy_from_user(&vendor_guid, setvariable.vendor_guid, 260*ff6301daSIvan Hu sizeof(vendor_guid))) 261*ff6301daSIvan Hu return -EFAULT; 262*ff6301daSIvan Hu 263*ff6301daSIvan Hu if (setvariable.variable_name) { 264*ff6301daSIvan Hu rv = copy_ucs2_from_user(&name, setvariable.variable_name); 265*ff6301daSIvan Hu if (rv) 266*ff6301daSIvan Hu return rv; 267*ff6301daSIvan Hu } 268*ff6301daSIvan Hu 269*ff6301daSIvan Hu data = kmalloc(setvariable.data_size, GFP_KERNEL); 270*ff6301daSIvan Hu if (!data) { 271*ff6301daSIvan Hu kfree(name); 272*ff6301daSIvan Hu return -ENOMEM; 273*ff6301daSIvan Hu } 274*ff6301daSIvan Hu if (copy_from_user(data, setvariable.data, setvariable.data_size)) { 275*ff6301daSIvan Hu rv = -EFAULT; 276*ff6301daSIvan Hu goto out; 277*ff6301daSIvan Hu } 278*ff6301daSIvan Hu 279*ff6301daSIvan Hu status = efi.set_variable(name, &vendor_guid, 280*ff6301daSIvan Hu setvariable.attributes, 281*ff6301daSIvan Hu setvariable.data_size, data); 282*ff6301daSIvan Hu 283*ff6301daSIvan Hu if (put_user(status, setvariable.status)) { 284*ff6301daSIvan Hu rv = -EFAULT; 285*ff6301daSIvan Hu goto out; 286*ff6301daSIvan Hu } 287*ff6301daSIvan Hu 288*ff6301daSIvan Hu rv = status == EFI_SUCCESS ? 0 : -EINVAL; 289*ff6301daSIvan Hu 290*ff6301daSIvan Hu out: 291*ff6301daSIvan Hu kfree(data); 292*ff6301daSIvan Hu kfree(name); 293*ff6301daSIvan Hu 294*ff6301daSIvan Hu return rv; 295*ff6301daSIvan Hu } 296*ff6301daSIvan Hu 297*ff6301daSIvan Hu static long efi_runtime_get_time(unsigned long arg) 298*ff6301daSIvan Hu { 299*ff6301daSIvan Hu struct efi_gettime __user *gettime_user; 300*ff6301daSIvan Hu struct efi_gettime gettime; 301*ff6301daSIvan Hu efi_status_t status; 302*ff6301daSIvan Hu efi_time_cap_t cap; 303*ff6301daSIvan Hu efi_time_t efi_time; 304*ff6301daSIvan Hu 305*ff6301daSIvan Hu gettime_user = (struct efi_gettime __user *)arg; 306*ff6301daSIvan Hu if (copy_from_user(&gettime, gettime_user, sizeof(gettime))) 307*ff6301daSIvan Hu return -EFAULT; 308*ff6301daSIvan Hu 309*ff6301daSIvan Hu status = efi.get_time(gettime.time ? &efi_time : NULL, 310*ff6301daSIvan Hu gettime.capabilities ? &cap : NULL); 311*ff6301daSIvan Hu 312*ff6301daSIvan Hu if (put_user(status, gettime.status)) 313*ff6301daSIvan Hu return -EFAULT; 314*ff6301daSIvan Hu 315*ff6301daSIvan Hu if (status != EFI_SUCCESS) 316*ff6301daSIvan Hu return -EINVAL; 317*ff6301daSIvan Hu 318*ff6301daSIvan Hu if (gettime.capabilities) { 319*ff6301daSIvan Hu efi_time_cap_t __user *cap_local; 320*ff6301daSIvan Hu 321*ff6301daSIvan Hu cap_local = (efi_time_cap_t *)gettime.capabilities; 322*ff6301daSIvan Hu if (put_user(cap.resolution, &(cap_local->resolution)) || 323*ff6301daSIvan Hu put_user(cap.accuracy, &(cap_local->accuracy)) || 324*ff6301daSIvan Hu put_user(cap.sets_to_zero, &(cap_local->sets_to_zero))) 325*ff6301daSIvan Hu return -EFAULT; 326*ff6301daSIvan Hu } 327*ff6301daSIvan Hu if (gettime.time) { 328*ff6301daSIvan Hu if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t))) 329*ff6301daSIvan Hu return -EFAULT; 330*ff6301daSIvan Hu } 331*ff6301daSIvan Hu 332*ff6301daSIvan Hu return 0; 333*ff6301daSIvan Hu } 334*ff6301daSIvan Hu 335*ff6301daSIvan Hu static long efi_runtime_set_time(unsigned long arg) 336*ff6301daSIvan Hu { 337*ff6301daSIvan Hu struct efi_settime __user *settime_user; 338*ff6301daSIvan Hu struct efi_settime settime; 339*ff6301daSIvan Hu efi_status_t status; 340*ff6301daSIvan Hu efi_time_t efi_time; 341*ff6301daSIvan Hu 342*ff6301daSIvan Hu settime_user = (struct efi_settime __user *)arg; 343*ff6301daSIvan Hu if (copy_from_user(&settime, settime_user, sizeof(settime))) 344*ff6301daSIvan Hu return -EFAULT; 345*ff6301daSIvan Hu if (copy_from_user(&efi_time, settime.time, 346*ff6301daSIvan Hu sizeof(efi_time_t))) 347*ff6301daSIvan Hu return -EFAULT; 348*ff6301daSIvan Hu status = efi.set_time(&efi_time); 349*ff6301daSIvan Hu 350*ff6301daSIvan Hu if (put_user(status, settime.status)) 351*ff6301daSIvan Hu return -EFAULT; 352*ff6301daSIvan Hu 353*ff6301daSIvan Hu return status == EFI_SUCCESS ? 0 : -EINVAL; 354*ff6301daSIvan Hu } 355*ff6301daSIvan Hu 356*ff6301daSIvan Hu static long efi_runtime_get_waketime(unsigned long arg) 357*ff6301daSIvan Hu { 358*ff6301daSIvan Hu struct efi_getwakeuptime __user *getwakeuptime_user; 359*ff6301daSIvan Hu struct efi_getwakeuptime getwakeuptime; 360*ff6301daSIvan Hu efi_bool_t enabled, pending; 361*ff6301daSIvan Hu efi_status_t status; 362*ff6301daSIvan Hu efi_time_t efi_time; 363*ff6301daSIvan Hu 364*ff6301daSIvan Hu getwakeuptime_user = (struct efi_getwakeuptime __user *)arg; 365*ff6301daSIvan Hu if (copy_from_user(&getwakeuptime, getwakeuptime_user, 366*ff6301daSIvan Hu sizeof(getwakeuptime))) 367*ff6301daSIvan Hu return -EFAULT; 368*ff6301daSIvan Hu 369*ff6301daSIvan Hu status = efi.get_wakeup_time( 370*ff6301daSIvan Hu getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL, 371*ff6301daSIvan Hu getwakeuptime.pending ? (efi_bool_t *)&pending : NULL, 372*ff6301daSIvan Hu getwakeuptime.time ? &efi_time : NULL); 373*ff6301daSIvan Hu 374*ff6301daSIvan Hu if (put_user(status, getwakeuptime.status)) 375*ff6301daSIvan Hu return -EFAULT; 376*ff6301daSIvan Hu 377*ff6301daSIvan Hu if (status != EFI_SUCCESS) 378*ff6301daSIvan Hu return -EINVAL; 379*ff6301daSIvan Hu 380*ff6301daSIvan Hu if (getwakeuptime.enabled && put_user(enabled, 381*ff6301daSIvan Hu getwakeuptime.enabled)) 382*ff6301daSIvan Hu return -EFAULT; 383*ff6301daSIvan Hu 384*ff6301daSIvan Hu if (getwakeuptime.time) { 385*ff6301daSIvan Hu if (copy_to_user(getwakeuptime.time, &efi_time, 386*ff6301daSIvan Hu sizeof(efi_time_t))) 387*ff6301daSIvan Hu return -EFAULT; 388*ff6301daSIvan Hu } 389*ff6301daSIvan Hu 390*ff6301daSIvan Hu return 0; 391*ff6301daSIvan Hu } 392*ff6301daSIvan Hu 393*ff6301daSIvan Hu static long efi_runtime_set_waketime(unsigned long arg) 394*ff6301daSIvan Hu { 395*ff6301daSIvan Hu struct efi_setwakeuptime __user *setwakeuptime_user; 396*ff6301daSIvan Hu struct efi_setwakeuptime setwakeuptime; 397*ff6301daSIvan Hu efi_bool_t enabled; 398*ff6301daSIvan Hu efi_status_t status; 399*ff6301daSIvan Hu efi_time_t efi_time; 400*ff6301daSIvan Hu 401*ff6301daSIvan Hu setwakeuptime_user = (struct efi_setwakeuptime __user *)arg; 402*ff6301daSIvan Hu 403*ff6301daSIvan Hu if (copy_from_user(&setwakeuptime, setwakeuptime_user, 404*ff6301daSIvan Hu sizeof(setwakeuptime))) 405*ff6301daSIvan Hu return -EFAULT; 406*ff6301daSIvan Hu 407*ff6301daSIvan Hu enabled = setwakeuptime.enabled; 408*ff6301daSIvan Hu if (setwakeuptime.time) { 409*ff6301daSIvan Hu if (copy_from_user(&efi_time, setwakeuptime.time, 410*ff6301daSIvan Hu sizeof(efi_time_t))) 411*ff6301daSIvan Hu return -EFAULT; 412*ff6301daSIvan Hu 413*ff6301daSIvan Hu status = efi.set_wakeup_time(enabled, &efi_time); 414*ff6301daSIvan Hu } else 415*ff6301daSIvan Hu status = efi.set_wakeup_time(enabled, NULL); 416*ff6301daSIvan Hu 417*ff6301daSIvan Hu if (put_user(status, setwakeuptime.status)) 418*ff6301daSIvan Hu return -EFAULT; 419*ff6301daSIvan Hu 420*ff6301daSIvan Hu return status == EFI_SUCCESS ? 0 : -EINVAL; 421*ff6301daSIvan Hu } 422*ff6301daSIvan Hu 423*ff6301daSIvan Hu static long efi_runtime_get_nextvariablename(unsigned long arg) 424*ff6301daSIvan Hu { 425*ff6301daSIvan Hu struct efi_getnextvariablename __user *getnextvariablename_user; 426*ff6301daSIvan Hu struct efi_getnextvariablename getnextvariablename; 427*ff6301daSIvan Hu unsigned long name_size, prev_name_size = 0, *ns = NULL; 428*ff6301daSIvan Hu efi_status_t status; 429*ff6301daSIvan Hu efi_guid_t *vd = NULL; 430*ff6301daSIvan Hu efi_guid_t vendor_guid; 431*ff6301daSIvan Hu efi_char16_t *name = NULL; 432*ff6301daSIvan Hu int rv; 433*ff6301daSIvan Hu 434*ff6301daSIvan Hu getnextvariablename_user = (struct efi_getnextvariablename __user *)arg; 435*ff6301daSIvan Hu 436*ff6301daSIvan Hu if (copy_from_user(&getnextvariablename, getnextvariablename_user, 437*ff6301daSIvan Hu sizeof(getnextvariablename))) 438*ff6301daSIvan Hu return -EFAULT; 439*ff6301daSIvan Hu 440*ff6301daSIvan Hu if (getnextvariablename.variable_name_size) { 441*ff6301daSIvan Hu if (get_user(name_size, getnextvariablename.variable_name_size)) 442*ff6301daSIvan Hu return -EFAULT; 443*ff6301daSIvan Hu ns = &name_size; 444*ff6301daSIvan Hu prev_name_size = name_size; 445*ff6301daSIvan Hu } 446*ff6301daSIvan Hu 447*ff6301daSIvan Hu if (getnextvariablename.vendor_guid) { 448*ff6301daSIvan Hu if (copy_from_user(&vendor_guid, 449*ff6301daSIvan Hu getnextvariablename.vendor_guid, 450*ff6301daSIvan Hu sizeof(vendor_guid))) 451*ff6301daSIvan Hu return -EFAULT; 452*ff6301daSIvan Hu vd = &vendor_guid; 453*ff6301daSIvan Hu } 454*ff6301daSIvan Hu 455*ff6301daSIvan Hu if (getnextvariablename.variable_name) { 456*ff6301daSIvan Hu size_t name_string_size = 0; 457*ff6301daSIvan Hu 458*ff6301daSIvan Hu rv = get_ucs2_strsize_from_user( 459*ff6301daSIvan Hu getnextvariablename.variable_name, 460*ff6301daSIvan Hu &name_string_size); 461*ff6301daSIvan Hu if (rv) 462*ff6301daSIvan Hu return rv; 463*ff6301daSIvan Hu /* 464*ff6301daSIvan Hu * The name_size may be smaller than the real buffer size where 465*ff6301daSIvan Hu * variable name located in some use cases. The most typical 466*ff6301daSIvan Hu * case is passing a 0 to get the required buffer size for the 467*ff6301daSIvan Hu * 1st time call. So we need to copy the content from user 468*ff6301daSIvan Hu * space for at least the string size of variable name, or else 469*ff6301daSIvan Hu * the name passed to UEFI may not be terminated as we expected. 470*ff6301daSIvan Hu */ 471*ff6301daSIvan Hu rv = copy_ucs2_from_user_len(&name, 472*ff6301daSIvan Hu getnextvariablename.variable_name, 473*ff6301daSIvan Hu prev_name_size > name_string_size ? 474*ff6301daSIvan Hu prev_name_size : name_string_size); 475*ff6301daSIvan Hu if (rv) 476*ff6301daSIvan Hu return rv; 477*ff6301daSIvan Hu } 478*ff6301daSIvan Hu 479*ff6301daSIvan Hu status = efi.get_next_variable(ns, name, vd); 480*ff6301daSIvan Hu 481*ff6301daSIvan Hu if (put_user(status, getnextvariablename.status)) { 482*ff6301daSIvan Hu rv = -EFAULT; 483*ff6301daSIvan Hu goto out; 484*ff6301daSIvan Hu } 485*ff6301daSIvan Hu 486*ff6301daSIvan Hu if (status != EFI_SUCCESS) { 487*ff6301daSIvan Hu if (status == EFI_BUFFER_TOO_SMALL) { 488*ff6301daSIvan Hu if (ns && put_user(*ns, 489*ff6301daSIvan Hu getnextvariablename.variable_name_size)) { 490*ff6301daSIvan Hu rv = -EFAULT; 491*ff6301daSIvan Hu goto out; 492*ff6301daSIvan Hu } 493*ff6301daSIvan Hu } 494*ff6301daSIvan Hu rv = -EINVAL; 495*ff6301daSIvan Hu goto out; 496*ff6301daSIvan Hu } 497*ff6301daSIvan Hu 498*ff6301daSIvan Hu if (name) { 499*ff6301daSIvan Hu if (copy_ucs2_to_user_len(getnextvariablename.variable_name, 500*ff6301daSIvan Hu name, prev_name_size)) { 501*ff6301daSIvan Hu rv = -EFAULT; 502*ff6301daSIvan Hu goto out; 503*ff6301daSIvan Hu } 504*ff6301daSIvan Hu } 505*ff6301daSIvan Hu 506*ff6301daSIvan Hu if (ns) { 507*ff6301daSIvan Hu if (put_user(*ns, getnextvariablename.variable_name_size)) { 508*ff6301daSIvan Hu rv = -EFAULT; 509*ff6301daSIvan Hu goto out; 510*ff6301daSIvan Hu } 511*ff6301daSIvan Hu } 512*ff6301daSIvan Hu 513*ff6301daSIvan Hu if (vd) { 514*ff6301daSIvan Hu if (copy_to_user(getnextvariablename.vendor_guid, vd, 515*ff6301daSIvan Hu sizeof(efi_guid_t))) 516*ff6301daSIvan Hu rv = -EFAULT; 517*ff6301daSIvan Hu } 518*ff6301daSIvan Hu 519*ff6301daSIvan Hu out: 520*ff6301daSIvan Hu kfree(name); 521*ff6301daSIvan Hu return rv; 522*ff6301daSIvan Hu } 523*ff6301daSIvan Hu 524*ff6301daSIvan Hu static long efi_runtime_get_nexthighmonocount(unsigned long arg) 525*ff6301daSIvan Hu { 526*ff6301daSIvan Hu struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user; 527*ff6301daSIvan Hu struct efi_getnexthighmonotoniccount getnexthighmonocount; 528*ff6301daSIvan Hu efi_status_t status; 529*ff6301daSIvan Hu u32 count; 530*ff6301daSIvan Hu 531*ff6301daSIvan Hu getnexthighmonocount_user = (struct 532*ff6301daSIvan Hu efi_getnexthighmonotoniccount __user *)arg; 533*ff6301daSIvan Hu 534*ff6301daSIvan Hu if (copy_from_user(&getnexthighmonocount, 535*ff6301daSIvan Hu getnexthighmonocount_user, 536*ff6301daSIvan Hu sizeof(getnexthighmonocount))) 537*ff6301daSIvan Hu return -EFAULT; 538*ff6301daSIvan Hu 539*ff6301daSIvan Hu status = efi.get_next_high_mono_count( 540*ff6301daSIvan Hu getnexthighmonocount.high_count ? &count : NULL); 541*ff6301daSIvan Hu 542*ff6301daSIvan Hu if (put_user(status, getnexthighmonocount.status)) 543*ff6301daSIvan Hu return -EFAULT; 544*ff6301daSIvan Hu 545*ff6301daSIvan Hu if (status != EFI_SUCCESS) 546*ff6301daSIvan Hu return -EINVAL; 547*ff6301daSIvan Hu 548*ff6301daSIvan Hu if (getnexthighmonocount.high_count && 549*ff6301daSIvan Hu put_user(count, getnexthighmonocount.high_count)) 550*ff6301daSIvan Hu return -EFAULT; 551*ff6301daSIvan Hu 552*ff6301daSIvan Hu return 0; 553*ff6301daSIvan Hu } 554*ff6301daSIvan Hu 555*ff6301daSIvan Hu static long efi_runtime_query_variableinfo(unsigned long arg) 556*ff6301daSIvan Hu { 557*ff6301daSIvan Hu struct efi_queryvariableinfo __user *queryvariableinfo_user; 558*ff6301daSIvan Hu struct efi_queryvariableinfo queryvariableinfo; 559*ff6301daSIvan Hu efi_status_t status; 560*ff6301daSIvan Hu u64 max_storage, remaining, max_size; 561*ff6301daSIvan Hu 562*ff6301daSIvan Hu queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg; 563*ff6301daSIvan Hu 564*ff6301daSIvan Hu if (copy_from_user(&queryvariableinfo, queryvariableinfo_user, 565*ff6301daSIvan Hu sizeof(queryvariableinfo))) 566*ff6301daSIvan Hu return -EFAULT; 567*ff6301daSIvan Hu 568*ff6301daSIvan Hu status = efi.query_variable_info(queryvariableinfo.attributes, 569*ff6301daSIvan Hu &max_storage, &remaining, &max_size); 570*ff6301daSIvan Hu 571*ff6301daSIvan Hu if (put_user(status, queryvariableinfo.status)) 572*ff6301daSIvan Hu return -EFAULT; 573*ff6301daSIvan Hu 574*ff6301daSIvan Hu if (status != EFI_SUCCESS) 575*ff6301daSIvan Hu return -EINVAL; 576*ff6301daSIvan Hu 577*ff6301daSIvan Hu if (put_user(max_storage, 578*ff6301daSIvan Hu queryvariableinfo.maximum_variable_storage_size)) 579*ff6301daSIvan Hu return -EFAULT; 580*ff6301daSIvan Hu 581*ff6301daSIvan Hu if (put_user(remaining, 582*ff6301daSIvan Hu queryvariableinfo.remaining_variable_storage_size)) 583*ff6301daSIvan Hu return -EFAULT; 584*ff6301daSIvan Hu 585*ff6301daSIvan Hu if (put_user(max_size, queryvariableinfo.maximum_variable_size)) 586*ff6301daSIvan Hu return -EFAULT; 587*ff6301daSIvan Hu 588*ff6301daSIvan Hu return 0; 589*ff6301daSIvan Hu } 590*ff6301daSIvan Hu 591*ff6301daSIvan Hu static long efi_runtime_query_capsulecaps(unsigned long arg) 592*ff6301daSIvan Hu { 593*ff6301daSIvan Hu struct efi_querycapsulecapabilities __user *qcaps_user; 594*ff6301daSIvan Hu struct efi_querycapsulecapabilities qcaps; 595*ff6301daSIvan Hu efi_capsule_header_t *capsules; 596*ff6301daSIvan Hu efi_status_t status; 597*ff6301daSIvan Hu u64 max_size; 598*ff6301daSIvan Hu int i, reset_type; 599*ff6301daSIvan Hu int rv = 0; 600*ff6301daSIvan Hu 601*ff6301daSIvan Hu qcaps_user = (struct efi_querycapsulecapabilities __user *)arg; 602*ff6301daSIvan Hu 603*ff6301daSIvan Hu if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps))) 604*ff6301daSIvan Hu return -EFAULT; 605*ff6301daSIvan Hu 606*ff6301daSIvan Hu capsules = kcalloc(qcaps.capsule_count + 1, 607*ff6301daSIvan Hu sizeof(efi_capsule_header_t), GFP_KERNEL); 608*ff6301daSIvan Hu if (!capsules) 609*ff6301daSIvan Hu return -ENOMEM; 610*ff6301daSIvan Hu 611*ff6301daSIvan Hu for (i = 0; i < qcaps.capsule_count; i++) { 612*ff6301daSIvan Hu efi_capsule_header_t *c; 613*ff6301daSIvan Hu /* 614*ff6301daSIvan Hu * We cannot dereference qcaps.capsule_header_array directly to 615*ff6301daSIvan Hu * obtain the address of the capsule as it resides in the 616*ff6301daSIvan Hu * user space 617*ff6301daSIvan Hu */ 618*ff6301daSIvan Hu if (get_user(c, qcaps.capsule_header_array + i)) { 619*ff6301daSIvan Hu rv = -EFAULT; 620*ff6301daSIvan Hu goto out; 621*ff6301daSIvan Hu } 622*ff6301daSIvan Hu if (copy_from_user(&capsules[i], c, 623*ff6301daSIvan Hu sizeof(efi_capsule_header_t))) { 624*ff6301daSIvan Hu rv = -EFAULT; 625*ff6301daSIvan Hu goto out; 626*ff6301daSIvan Hu } 627*ff6301daSIvan Hu } 628*ff6301daSIvan Hu 629*ff6301daSIvan Hu qcaps.capsule_header_array = &capsules; 630*ff6301daSIvan Hu 631*ff6301daSIvan Hu status = efi.query_capsule_caps((efi_capsule_header_t **) 632*ff6301daSIvan Hu qcaps.capsule_header_array, 633*ff6301daSIvan Hu qcaps.capsule_count, 634*ff6301daSIvan Hu &max_size, &reset_type); 635*ff6301daSIvan Hu 636*ff6301daSIvan Hu if (put_user(status, qcaps.status)) { 637*ff6301daSIvan Hu rv = -EFAULT; 638*ff6301daSIvan Hu goto out; 639*ff6301daSIvan Hu } 640*ff6301daSIvan Hu 641*ff6301daSIvan Hu if (status != EFI_SUCCESS) { 642*ff6301daSIvan Hu rv = -EINVAL; 643*ff6301daSIvan Hu goto out; 644*ff6301daSIvan Hu } 645*ff6301daSIvan Hu 646*ff6301daSIvan Hu if (put_user(max_size, qcaps.maximum_capsule_size)) { 647*ff6301daSIvan Hu rv = -EFAULT; 648*ff6301daSIvan Hu goto out; 649*ff6301daSIvan Hu } 650*ff6301daSIvan Hu 651*ff6301daSIvan Hu if (put_user(reset_type, qcaps.reset_type)) 652*ff6301daSIvan Hu rv = -EFAULT; 653*ff6301daSIvan Hu 654*ff6301daSIvan Hu out: 655*ff6301daSIvan Hu kfree(capsules); 656*ff6301daSIvan Hu return rv; 657*ff6301daSIvan Hu } 658*ff6301daSIvan Hu 659*ff6301daSIvan Hu static long efi_test_ioctl(struct file *file, unsigned int cmd, 660*ff6301daSIvan Hu unsigned long arg) 661*ff6301daSIvan Hu { 662*ff6301daSIvan Hu switch (cmd) { 663*ff6301daSIvan Hu case EFI_RUNTIME_GET_VARIABLE: 664*ff6301daSIvan Hu return efi_runtime_get_variable(arg); 665*ff6301daSIvan Hu 666*ff6301daSIvan Hu case EFI_RUNTIME_SET_VARIABLE: 667*ff6301daSIvan Hu return efi_runtime_set_variable(arg); 668*ff6301daSIvan Hu 669*ff6301daSIvan Hu case EFI_RUNTIME_GET_TIME: 670*ff6301daSIvan Hu return efi_runtime_get_time(arg); 671*ff6301daSIvan Hu 672*ff6301daSIvan Hu case EFI_RUNTIME_SET_TIME: 673*ff6301daSIvan Hu return efi_runtime_set_time(arg); 674*ff6301daSIvan Hu 675*ff6301daSIvan Hu case EFI_RUNTIME_GET_WAKETIME: 676*ff6301daSIvan Hu return efi_runtime_get_waketime(arg); 677*ff6301daSIvan Hu 678*ff6301daSIvan Hu case EFI_RUNTIME_SET_WAKETIME: 679*ff6301daSIvan Hu return efi_runtime_set_waketime(arg); 680*ff6301daSIvan Hu 681*ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTVARIABLENAME: 682*ff6301daSIvan Hu return efi_runtime_get_nextvariablename(arg); 683*ff6301daSIvan Hu 684*ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT: 685*ff6301daSIvan Hu return efi_runtime_get_nexthighmonocount(arg); 686*ff6301daSIvan Hu 687*ff6301daSIvan Hu case EFI_RUNTIME_QUERY_VARIABLEINFO: 688*ff6301daSIvan Hu return efi_runtime_query_variableinfo(arg); 689*ff6301daSIvan Hu 690*ff6301daSIvan Hu case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES: 691*ff6301daSIvan Hu return efi_runtime_query_capsulecaps(arg); 692*ff6301daSIvan Hu } 693*ff6301daSIvan Hu 694*ff6301daSIvan Hu return -ENOTTY; 695*ff6301daSIvan Hu } 696*ff6301daSIvan Hu 697*ff6301daSIvan Hu static int efi_test_open(struct inode *inode, struct file *file) 698*ff6301daSIvan Hu { 699*ff6301daSIvan Hu /* 700*ff6301daSIvan Hu * nothing special to do here 701*ff6301daSIvan Hu * We do accept multiple open files at the same time as we 702*ff6301daSIvan Hu * synchronize on the per call operation. 703*ff6301daSIvan Hu */ 704*ff6301daSIvan Hu return 0; 705*ff6301daSIvan Hu } 706*ff6301daSIvan Hu 707*ff6301daSIvan Hu static int efi_test_close(struct inode *inode, struct file *file) 708*ff6301daSIvan Hu { 709*ff6301daSIvan Hu return 0; 710*ff6301daSIvan Hu } 711*ff6301daSIvan Hu 712*ff6301daSIvan Hu /* 713*ff6301daSIvan Hu * The various file operations we support. 714*ff6301daSIvan Hu */ 715*ff6301daSIvan Hu static const struct file_operations efi_test_fops = { 716*ff6301daSIvan Hu .owner = THIS_MODULE, 717*ff6301daSIvan Hu .unlocked_ioctl = efi_test_ioctl, 718*ff6301daSIvan Hu .open = efi_test_open, 719*ff6301daSIvan Hu .release = efi_test_close, 720*ff6301daSIvan Hu .llseek = no_llseek, 721*ff6301daSIvan Hu }; 722*ff6301daSIvan Hu 723*ff6301daSIvan Hu static struct miscdevice efi_test_dev = { 724*ff6301daSIvan Hu MISC_DYNAMIC_MINOR, 725*ff6301daSIvan Hu "efi_test", 726*ff6301daSIvan Hu &efi_test_fops 727*ff6301daSIvan Hu }; 728*ff6301daSIvan Hu 729*ff6301daSIvan Hu static int __init efi_test_init(void) 730*ff6301daSIvan Hu { 731*ff6301daSIvan Hu int ret; 732*ff6301daSIvan Hu 733*ff6301daSIvan Hu ret = misc_register(&efi_test_dev); 734*ff6301daSIvan Hu if (ret) { 735*ff6301daSIvan Hu pr_err("efi_test: can't misc_register on minor=%d\n", 736*ff6301daSIvan Hu MISC_DYNAMIC_MINOR); 737*ff6301daSIvan Hu return ret; 738*ff6301daSIvan Hu } 739*ff6301daSIvan Hu 740*ff6301daSIvan Hu return 0; 741*ff6301daSIvan Hu } 742*ff6301daSIvan Hu 743*ff6301daSIvan Hu static void __exit efi_test_exit(void) 744*ff6301daSIvan Hu { 745*ff6301daSIvan Hu misc_deregister(&efi_test_dev); 746*ff6301daSIvan Hu } 747*ff6301daSIvan Hu 748*ff6301daSIvan Hu module_init(efi_test_init); 749*ff6301daSIvan Hu module_exit(efi_test_exit); 750