1*952667daSRoger Pau Monné /*- 2*952667daSRoger Pau Monné * Copyright (c) 2021 Citrix Systems R&D 3*952667daSRoger Pau Monné * All rights reserved. 4*952667daSRoger Pau Monné * 5*952667daSRoger Pau Monné * Redistribution and use in source and binary forms, with or without 6*952667daSRoger Pau Monné * modification, are permitted provided that the following conditions 7*952667daSRoger Pau Monné * are met: 8*952667daSRoger Pau Monné * 9*952667daSRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 10*952667daSRoger Pau Monné * notice, this list of conditions and the following disclaimer. 11*952667daSRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 12*952667daSRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 13*952667daSRoger Pau Monné * documentation and/or other materials provided with the distribution. 14*952667daSRoger Pau Monné * 15*952667daSRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*952667daSRoger Pau Monné * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*952667daSRoger Pau Monné * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*952667daSRoger Pau Monné * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*952667daSRoger Pau Monné * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*952667daSRoger Pau Monné * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*952667daSRoger Pau Monné * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*952667daSRoger Pau Monné * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*952667daSRoger Pau Monné * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*952667daSRoger Pau Monné * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*952667daSRoger Pau Monné */ 26*952667daSRoger Pau Monné 27*952667daSRoger Pau Monné #include <sys/cdefs.h> 28*952667daSRoger Pau Monné __FBSDID("$FreeBSD$"); 29*952667daSRoger Pau Monné 30*952667daSRoger Pau Monné #include <sys/param.h> 31*952667daSRoger Pau Monné #include <sys/efi.h> 32*952667daSRoger Pau Monné #include <sys/eventhandler.h> 33*952667daSRoger Pau Monné #include <sys/kernel.h> 34*952667daSRoger Pau Monné #include <sys/linker.h> 35*952667daSRoger Pau Monné #include <sys/module.h> 36*952667daSRoger Pau Monné #include <sys/clock.h> 37*952667daSRoger Pau Monné #include <sys/sysctl.h> 38*952667daSRoger Pau Monné #include <sys/systm.h> 39*952667daSRoger Pau Monné 40*952667daSRoger Pau Monné #include <xen/xen-os.h> 41*952667daSRoger Pau Monné #include <xen/error.h> 42*952667daSRoger Pau Monné #include <xen/hypervisor.h> 43*952667daSRoger Pau Monné 44*952667daSRoger Pau Monné #include <xen/interface/platform.h> 45*952667daSRoger Pau Monné 46*952667daSRoger Pau Monné extern char bootmethod[16]; 47*952667daSRoger Pau Monné 48*952667daSRoger Pau Monné static int 49*952667daSRoger Pau Monné rt_ok(void) 50*952667daSRoger Pau Monné { 51*952667daSRoger Pau Monné 52*952667daSRoger Pau Monné return (0); 53*952667daSRoger Pau Monné } 54*952667daSRoger Pau Monné 55*952667daSRoger Pau Monné static int 56*952667daSRoger Pau Monné get_time(struct efi_tm *tm) 57*952667daSRoger Pau Monné { 58*952667daSRoger Pau Monné struct xen_platform_op op = { 59*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 60*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 61*952667daSRoger Pau Monné }; 62*952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 63*952667daSRoger Pau Monné int error; 64*952667daSRoger Pau Monné 65*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 66*952667daSRoger Pau Monné if (error != 0) 67*952667daSRoger Pau Monné return (xen_translate_error(error)); 68*952667daSRoger Pau Monné 69*952667daSRoger Pau Monné tm->tm_year = call->u.get_time.time.year; 70*952667daSRoger Pau Monné tm->tm_mon = call->u.get_time.time.month; 71*952667daSRoger Pau Monné tm->tm_mday = call->u.get_time.time.day; 72*952667daSRoger Pau Monné tm->tm_hour = call->u.get_time.time.hour; 73*952667daSRoger Pau Monné tm->tm_min = call->u.get_time.time.min; 74*952667daSRoger Pau Monné tm->tm_sec = call->u.get_time.time.sec; 75*952667daSRoger Pau Monné tm->tm_nsec = call->u.get_time.time.ns; 76*952667daSRoger Pau Monné tm->tm_tz = call->u.get_time.time.tz; 77*952667daSRoger Pau Monné tm->tm_dst = call->u.get_time.time.daylight; 78*952667daSRoger Pau Monné 79*952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 80*952667daSRoger Pau Monné } 81*952667daSRoger Pau Monné 82*952667daSRoger Pau Monné static int 83*952667daSRoger Pau Monné get_time_capabilities(struct efi_tmcap *tmcap) 84*952667daSRoger Pau Monné { 85*952667daSRoger Pau Monné struct xen_platform_op op = { 86*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 87*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 88*952667daSRoger Pau Monné }; 89*952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 90*952667daSRoger Pau Monné int error; 91*952667daSRoger Pau Monné 92*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 93*952667daSRoger Pau Monné if (error != 0) 94*952667daSRoger Pau Monné return (xen_translate_error(error)); 95*952667daSRoger Pau Monné 96*952667daSRoger Pau Monné tmcap->tc_res = call->u.get_time.resolution; 97*952667daSRoger Pau Monné tmcap->tc_prec = call->u.get_time.accuracy; 98*952667daSRoger Pau Monné tmcap->tc_stz = call->misc & XEN_EFI_GET_TIME_SET_CLEARS_NS; 99*952667daSRoger Pau Monné 100*952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 101*952667daSRoger Pau Monné } 102*952667daSRoger Pau Monné 103*952667daSRoger Pau Monné static int 104*952667daSRoger Pau Monné set_time(struct efi_tm *tm) 105*952667daSRoger Pau Monné { 106*952667daSRoger Pau Monné struct xen_platform_op op = { 107*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 108*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 109*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.year = tm->tm_year, 110*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.month = tm->tm_mon, 111*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.day = tm->tm_mday, 112*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.hour = tm->tm_hour, 113*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.min = tm->tm_min, 114*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.sec = tm->tm_sec, 115*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.ns = tm->tm_nsec, 116*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.tz = tm->tm_tz, 117*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.daylight = tm->tm_dst, 118*952667daSRoger Pau Monné }; 119*952667daSRoger Pau Monné int error; 120*952667daSRoger Pau Monné 121*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 122*952667daSRoger Pau Monné 123*952667daSRoger Pau Monné return ((error != 0) ? xen_translate_error(error) : 124*952667daSRoger Pau Monné efi_status_to_errno(op.u.efi_runtime_call.status)); 125*952667daSRoger Pau Monné } 126*952667daSRoger Pau Monné 127*952667daSRoger Pau Monné static int 128*952667daSRoger Pau Monné var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, 129*952667daSRoger Pau Monné size_t *datasize, void *data) 130*952667daSRoger Pau Monné { 131*952667daSRoger Pau Monné struct xen_platform_op op = { 132*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 133*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_variable, 134*952667daSRoger Pau Monné .u.efi_runtime_call.u.get_variable.size = *datasize, 135*952667daSRoger Pau Monné }; 136*952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 137*952667daSRoger Pau Monné int error; 138*952667daSRoger Pau Monné 139*952667daSRoger Pau Monné CTASSERT(sizeof(*vendor) == sizeof(call->u.get_variable.vendor_guid)); 140*952667daSRoger Pau Monné 141*952667daSRoger Pau Monné memcpy(&call->u.get_variable.vendor_guid, vendor, 142*952667daSRoger Pau Monné sizeof(*vendor)); 143*952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_variable.name, name); 144*952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_variable.data, data); 145*952667daSRoger Pau Monné 146*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 147*952667daSRoger Pau Monné if (error != 0) 148*952667daSRoger Pau Monné return (xen_translate_error(error)); 149*952667daSRoger Pau Monné 150*952667daSRoger Pau Monné *attrib = call->misc; 151*952667daSRoger Pau Monné *datasize = call->u.get_variable.size; 152*952667daSRoger Pau Monné 153*952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 154*952667daSRoger Pau Monné } 155*952667daSRoger Pau Monné 156*952667daSRoger Pau Monné static int 157*952667daSRoger Pau Monné var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) 158*952667daSRoger Pau Monné { 159*952667daSRoger Pau Monné struct xen_platform_op op = { 160*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 161*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_next_variable_name, 162*952667daSRoger Pau Monné .u.efi_runtime_call.u.get_next_variable_name.size = *namesize, 163*952667daSRoger Pau Monné }; 164*952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 165*952667daSRoger Pau Monné int error; 166*952667daSRoger Pau Monné 167*952667daSRoger Pau Monné memcpy(&call->u.get_next_variable_name.vendor_guid, vendor, 168*952667daSRoger Pau Monné sizeof(*vendor)); 169*952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_next_variable_name.name, name); 170*952667daSRoger Pau Monné 171*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 172*952667daSRoger Pau Monné if (error != 0) 173*952667daSRoger Pau Monné return (xen_translate_error(error)); 174*952667daSRoger Pau Monné 175*952667daSRoger Pau Monné *namesize = call->u.get_next_variable_name.size; 176*952667daSRoger Pau Monné memcpy(vendor, &call->u.get_next_variable_name.vendor_guid, 177*952667daSRoger Pau Monné sizeof(*vendor)); 178*952667daSRoger Pau Monné 179*952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 180*952667daSRoger Pau Monné } 181*952667daSRoger Pau Monné 182*952667daSRoger Pau Monné static int 183*952667daSRoger Pau Monné var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, 184*952667daSRoger Pau Monné size_t datasize, void *data) 185*952667daSRoger Pau Monné { 186*952667daSRoger Pau Monné struct xen_platform_op op = { 187*952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 188*952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_set_variable, 189*952667daSRoger Pau Monné .u.efi_runtime_call.misc = attrib, 190*952667daSRoger Pau Monné .u.efi_runtime_call.u.set_variable.size = datasize, 191*952667daSRoger Pau Monné }; 192*952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 193*952667daSRoger Pau Monné int error; 194*952667daSRoger Pau Monné 195*952667daSRoger Pau Monné memcpy(&call->u.set_variable.vendor_guid, vendor, 196*952667daSRoger Pau Monné sizeof(*vendor)); 197*952667daSRoger Pau Monné set_xen_guest_handle(call->u.set_variable.name, name); 198*952667daSRoger Pau Monné set_xen_guest_handle(call->u.set_variable.data, data); 199*952667daSRoger Pau Monné 200*952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 201*952667daSRoger Pau Monné 202*952667daSRoger Pau Monné return ((error != 0) ? xen_translate_error(error) : 203*952667daSRoger Pau Monné efi_status_to_errno(call->status)); 204*952667daSRoger Pau Monné } 205*952667daSRoger Pau Monné 206*952667daSRoger Pau Monné const static struct efi_ops pvefi_ops = { 207*952667daSRoger Pau Monné .rt_ok = rt_ok, 208*952667daSRoger Pau Monné .get_time = get_time, 209*952667daSRoger Pau Monné .get_time_capabilities = get_time_capabilities, 210*952667daSRoger Pau Monné .set_time = set_time, 211*952667daSRoger Pau Monné .var_get = var_get, 212*952667daSRoger Pau Monné .var_nextname = var_nextname, 213*952667daSRoger Pau Monné .var_set = var_set, 214*952667daSRoger Pau Monné }; 215*952667daSRoger Pau Monné 216*952667daSRoger Pau Monné static int 217*952667daSRoger Pau Monné modevents(module_t m, int event, void *arg __unused) 218*952667daSRoger Pau Monné { 219*952667daSRoger Pau Monné const static struct efi_ops *prev; 220*952667daSRoger Pau Monné int rt_disabled; 221*952667daSRoger Pau Monné 222*952667daSRoger Pau Monné switch (event) { 223*952667daSRoger Pau Monné case MOD_LOAD: 224*952667daSRoger Pau Monné rt_disabled = 0; 225*952667daSRoger Pau Monné TUNABLE_INT_FETCH("efi.rt.disabled", &rt_disabled); 226*952667daSRoger Pau Monné 227*952667daSRoger Pau Monné if (!xen_initial_domain() || strcmp("UEFI", bootmethod) != 0 || 228*952667daSRoger Pau Monné rt_disabled == 1) 229*952667daSRoger Pau Monné return (0); 230*952667daSRoger Pau Monné 231*952667daSRoger Pau Monné prev = active_efi_ops; 232*952667daSRoger Pau Monné active_efi_ops = &pvefi_ops; 233*952667daSRoger Pau Monné return (0); 234*952667daSRoger Pau Monné 235*952667daSRoger Pau Monné case MOD_UNLOAD: 236*952667daSRoger Pau Monné if (prev != NULL) 237*952667daSRoger Pau Monné active_efi_ops = prev; 238*952667daSRoger Pau Monné return (0); 239*952667daSRoger Pau Monné 240*952667daSRoger Pau Monné case MOD_SHUTDOWN: 241*952667daSRoger Pau Monné return (0); 242*952667daSRoger Pau Monné 243*952667daSRoger Pau Monné default: 244*952667daSRoger Pau Monné return (EOPNOTSUPP); 245*952667daSRoger Pau Monné } 246*952667daSRoger Pau Monné } 247*952667daSRoger Pau Monné 248*952667daSRoger Pau Monné static moduledata_t moddata = { 249*952667daSRoger Pau Monné .name = "pvefirt", 250*952667daSRoger Pau Monné .evhand = modevents, 251*952667daSRoger Pau Monné .priv = NULL, 252*952667daSRoger Pau Monné }; 253*952667daSRoger Pau Monné /* After fpuinitstate, before efidev */ 254*952667daSRoger Pau Monné DECLARE_MODULE(pvefirt, moddata, SI_SUB_DRIVERS, SI_ORDER_SECOND); 255*952667daSRoger Pau Monné MODULE_VERSION(pvefirt, 1); 256