1952667daSRoger Pau Monné /*- 2952667daSRoger Pau Monné * Copyright (c) 2021 Citrix Systems R&D 3952667daSRoger Pau Monné * All rights reserved. 4952667daSRoger Pau Monné * 5952667daSRoger Pau Monné * Redistribution and use in source and binary forms, with or without 6952667daSRoger Pau Monné * modification, are permitted provided that the following conditions 7952667daSRoger Pau Monné * are met: 8952667daSRoger Pau Monné * 9952667daSRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 10952667daSRoger Pau Monné * notice, this list of conditions and the following disclaimer. 11952667daSRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 12952667daSRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 13952667daSRoger Pau Monné * documentation and/or other materials provided with the distribution. 14952667daSRoger Pau Monné * 15952667daSRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16952667daSRoger Pau Monné * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17952667daSRoger Pau Monné * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18952667daSRoger Pau Monné * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19952667daSRoger Pau Monné * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20952667daSRoger Pau Monné * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21952667daSRoger Pau Monné * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22952667daSRoger Pau Monné * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23952667daSRoger Pau Monné * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24952667daSRoger Pau Monné * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25952667daSRoger Pau Monné */ 26952667daSRoger Pau Monné 27952667daSRoger Pau Monné #include <sys/cdefs.h> 28952667daSRoger Pau Monné __FBSDID("$FreeBSD$"); 29952667daSRoger Pau Monné 30952667daSRoger Pau Monné #include <sys/param.h> 31952667daSRoger Pau Monné #include <sys/efi.h> 32952667daSRoger Pau Monné #include <sys/eventhandler.h> 33952667daSRoger Pau Monné #include <sys/kernel.h> 34952667daSRoger Pau Monné #include <sys/linker.h> 35952667daSRoger Pau Monné #include <sys/module.h> 36952667daSRoger Pau Monné #include <sys/clock.h> 37952667daSRoger Pau Monné #include <sys/sysctl.h> 38952667daSRoger Pau Monné #include <sys/systm.h> 39952667daSRoger Pau Monné 40952667daSRoger Pau Monné #include <xen/xen-os.h> 41952667daSRoger Pau Monné #include <xen/error.h> 42952667daSRoger Pau Monné #include <xen/hypervisor.h> 43952667daSRoger Pau Monné 44*ad7dd514SElliott Mitchell #include <contrib/xen/platform.h> 45952667daSRoger Pau Monné 46952667daSRoger Pau Monné extern char bootmethod[16]; 47952667daSRoger Pau Monné 48952667daSRoger Pau Monné static int 49952667daSRoger Pau Monné rt_ok(void) 50952667daSRoger Pau Monné { 51952667daSRoger Pau Monné 52952667daSRoger Pau Monné return (0); 53952667daSRoger Pau Monné } 54952667daSRoger Pau Monné 55952667daSRoger Pau Monné static int 56952667daSRoger Pau Monné get_time(struct efi_tm *tm) 57952667daSRoger Pau Monné { 58952667daSRoger Pau Monné struct xen_platform_op op = { 59952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 60952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 61952667daSRoger Pau Monné }; 62952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 63952667daSRoger Pau Monné int error; 64952667daSRoger Pau Monné 65952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 66952667daSRoger Pau Monné if (error != 0) 67952667daSRoger Pau Monné return (xen_translate_error(error)); 68952667daSRoger Pau Monné 69952667daSRoger Pau Monné tm->tm_year = call->u.get_time.time.year; 70952667daSRoger Pau Monné tm->tm_mon = call->u.get_time.time.month; 71952667daSRoger Pau Monné tm->tm_mday = call->u.get_time.time.day; 72952667daSRoger Pau Monné tm->tm_hour = call->u.get_time.time.hour; 73952667daSRoger Pau Monné tm->tm_min = call->u.get_time.time.min; 74952667daSRoger Pau Monné tm->tm_sec = call->u.get_time.time.sec; 75952667daSRoger Pau Monné tm->tm_nsec = call->u.get_time.time.ns; 76952667daSRoger Pau Monné tm->tm_tz = call->u.get_time.time.tz; 77952667daSRoger Pau Monné tm->tm_dst = call->u.get_time.time.daylight; 78952667daSRoger Pau Monné 79952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 80952667daSRoger Pau Monné } 81952667daSRoger Pau Monné 82952667daSRoger Pau Monné static int 83952667daSRoger Pau Monné get_time_capabilities(struct efi_tmcap *tmcap) 84952667daSRoger Pau Monné { 85952667daSRoger Pau Monné struct xen_platform_op op = { 86952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 87952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 88952667daSRoger Pau Monné }; 89952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 90952667daSRoger Pau Monné int error; 91952667daSRoger Pau Monné 92952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 93952667daSRoger Pau Monné if (error != 0) 94952667daSRoger Pau Monné return (xen_translate_error(error)); 95952667daSRoger Pau Monné 96952667daSRoger Pau Monné tmcap->tc_res = call->u.get_time.resolution; 97952667daSRoger Pau Monné tmcap->tc_prec = call->u.get_time.accuracy; 98952667daSRoger Pau Monné tmcap->tc_stz = call->misc & XEN_EFI_GET_TIME_SET_CLEARS_NS; 99952667daSRoger Pau Monné 100952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 101952667daSRoger Pau Monné } 102952667daSRoger Pau Monné 103952667daSRoger Pau Monné static int 104952667daSRoger Pau Monné set_time(struct efi_tm *tm) 105952667daSRoger Pau Monné { 106952667daSRoger Pau Monné struct xen_platform_op op = { 107952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 108952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_time, 109952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.year = tm->tm_year, 110952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.month = tm->tm_mon, 111952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.day = tm->tm_mday, 112952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.hour = tm->tm_hour, 113952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.min = tm->tm_min, 114952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.sec = tm->tm_sec, 115952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.ns = tm->tm_nsec, 116952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.tz = tm->tm_tz, 117952667daSRoger Pau Monné .u.efi_runtime_call.u.set_time.daylight = tm->tm_dst, 118952667daSRoger Pau Monné }; 119952667daSRoger Pau Monné int error; 120952667daSRoger Pau Monné 121952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 122952667daSRoger Pau Monné 123952667daSRoger Pau Monné return ((error != 0) ? xen_translate_error(error) : 124952667daSRoger Pau Monné efi_status_to_errno(op.u.efi_runtime_call.status)); 125952667daSRoger Pau Monné } 126952667daSRoger Pau Monné 127952667daSRoger Pau Monné static int 128952667daSRoger Pau Monné var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, 129952667daSRoger Pau Monné size_t *datasize, void *data) 130952667daSRoger Pau Monné { 131952667daSRoger Pau Monné struct xen_platform_op op = { 132952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 133952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_variable, 134952667daSRoger Pau Monné .u.efi_runtime_call.u.get_variable.size = *datasize, 135952667daSRoger Pau Monné }; 136952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 137952667daSRoger Pau Monné int error; 138952667daSRoger Pau Monné 139952667daSRoger Pau Monné CTASSERT(sizeof(*vendor) == sizeof(call->u.get_variable.vendor_guid)); 140952667daSRoger Pau Monné 141952667daSRoger Pau Monné memcpy(&call->u.get_variable.vendor_guid, vendor, 142952667daSRoger Pau Monné sizeof(*vendor)); 143952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_variable.name, name); 144952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_variable.data, data); 145952667daSRoger Pau Monné 146952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 147952667daSRoger Pau Monné if (error != 0) 148952667daSRoger Pau Monné return (xen_translate_error(error)); 149952667daSRoger Pau Monné 150952667daSRoger Pau Monné *attrib = call->misc; 151952667daSRoger Pau Monné *datasize = call->u.get_variable.size; 152952667daSRoger Pau Monné 153952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 154952667daSRoger Pau Monné } 155952667daSRoger Pau Monné 156952667daSRoger Pau Monné static int 157952667daSRoger Pau Monné var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) 158952667daSRoger Pau Monné { 159952667daSRoger Pau Monné struct xen_platform_op op = { 160952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 161952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_get_next_variable_name, 162952667daSRoger Pau Monné .u.efi_runtime_call.u.get_next_variable_name.size = *namesize, 163952667daSRoger Pau Monné }; 164952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 165952667daSRoger Pau Monné int error; 166952667daSRoger Pau Monné 167952667daSRoger Pau Monné memcpy(&call->u.get_next_variable_name.vendor_guid, vendor, 168952667daSRoger Pau Monné sizeof(*vendor)); 169952667daSRoger Pau Monné set_xen_guest_handle(call->u.get_next_variable_name.name, name); 170952667daSRoger Pau Monné 171952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 172952667daSRoger Pau Monné if (error != 0) 173952667daSRoger Pau Monné return (xen_translate_error(error)); 174952667daSRoger Pau Monné 175952667daSRoger Pau Monné *namesize = call->u.get_next_variable_name.size; 176952667daSRoger Pau Monné memcpy(vendor, &call->u.get_next_variable_name.vendor_guid, 177952667daSRoger Pau Monné sizeof(*vendor)); 178952667daSRoger Pau Monné 179952667daSRoger Pau Monné return (efi_status_to_errno(call->status)); 180952667daSRoger Pau Monné } 181952667daSRoger Pau Monné 182952667daSRoger Pau Monné static int 183952667daSRoger Pau Monné var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, 184952667daSRoger Pau Monné size_t datasize, void *data) 185952667daSRoger Pau Monné { 186952667daSRoger Pau Monné struct xen_platform_op op = { 187952667daSRoger Pau Monné .cmd = XENPF_efi_runtime_call, 188952667daSRoger Pau Monné .u.efi_runtime_call.function = XEN_EFI_set_variable, 189952667daSRoger Pau Monné .u.efi_runtime_call.misc = attrib, 190952667daSRoger Pau Monné .u.efi_runtime_call.u.set_variable.size = datasize, 191952667daSRoger Pau Monné }; 192952667daSRoger Pau Monné struct xenpf_efi_runtime_call *call = &op.u.efi_runtime_call; 193952667daSRoger Pau Monné int error; 194952667daSRoger Pau Monné 195952667daSRoger Pau Monné memcpy(&call->u.set_variable.vendor_guid, vendor, 196952667daSRoger Pau Monné sizeof(*vendor)); 197952667daSRoger Pau Monné set_xen_guest_handle(call->u.set_variable.name, name); 198952667daSRoger Pau Monné set_xen_guest_handle(call->u.set_variable.data, data); 199952667daSRoger Pau Monné 200952667daSRoger Pau Monné error = HYPERVISOR_platform_op(&op); 201952667daSRoger Pau Monné 202952667daSRoger Pau Monné return ((error != 0) ? xen_translate_error(error) : 203952667daSRoger Pau Monné efi_status_to_errno(call->status)); 204952667daSRoger Pau Monné } 205952667daSRoger Pau Monné 206952667daSRoger Pau Monné const static struct efi_ops pvefi_ops = { 207952667daSRoger Pau Monné .rt_ok = rt_ok, 208952667daSRoger Pau Monné .get_time = get_time, 209952667daSRoger Pau Monné .get_time_capabilities = get_time_capabilities, 210952667daSRoger Pau Monné .set_time = set_time, 211952667daSRoger Pau Monné .var_get = var_get, 212952667daSRoger Pau Monné .var_nextname = var_nextname, 213952667daSRoger Pau Monné .var_set = var_set, 214952667daSRoger Pau Monné }; 215952667daSRoger Pau Monné 216952667daSRoger Pau Monné static int 217952667daSRoger Pau Monné modevents(module_t m, int event, void *arg __unused) 218952667daSRoger Pau Monné { 219952667daSRoger Pau Monné const static struct efi_ops *prev; 220952667daSRoger Pau Monné int rt_disabled; 221952667daSRoger Pau Monné 222952667daSRoger Pau Monné switch (event) { 223952667daSRoger Pau Monné case MOD_LOAD: 224952667daSRoger Pau Monné rt_disabled = 0; 225952667daSRoger Pau Monné TUNABLE_INT_FETCH("efi.rt.disabled", &rt_disabled); 226952667daSRoger Pau Monné 227952667daSRoger Pau Monné if (!xen_initial_domain() || strcmp("UEFI", bootmethod) != 0 || 228952667daSRoger Pau Monné rt_disabled == 1) 229952667daSRoger Pau Monné return (0); 230952667daSRoger Pau Monné 231952667daSRoger Pau Monné prev = active_efi_ops; 232952667daSRoger Pau Monné active_efi_ops = &pvefi_ops; 233952667daSRoger Pau Monné return (0); 234952667daSRoger Pau Monné 235952667daSRoger Pau Monné case MOD_UNLOAD: 236952667daSRoger Pau Monné if (prev != NULL) 237952667daSRoger Pau Monné active_efi_ops = prev; 238952667daSRoger Pau Monné return (0); 239952667daSRoger Pau Monné 240952667daSRoger Pau Monné case MOD_SHUTDOWN: 241952667daSRoger Pau Monné return (0); 242952667daSRoger Pau Monné 243952667daSRoger Pau Monné default: 244952667daSRoger Pau Monné return (EOPNOTSUPP); 245952667daSRoger Pau Monné } 246952667daSRoger Pau Monné } 247952667daSRoger Pau Monné 248952667daSRoger Pau Monné static moduledata_t moddata = { 249952667daSRoger Pau Monné .name = "pvefirt", 250952667daSRoger Pau Monné .evhand = modevents, 251952667daSRoger Pau Monné .priv = NULL, 252952667daSRoger Pau Monné }; 253952667daSRoger Pau Monné /* After fpuinitstate, before efidev */ 254952667daSRoger Pau Monné DECLARE_MODULE(pvefirt, moddata, SI_SUB_DRIVERS, SI_ORDER_SECOND); 255952667daSRoger Pau Monné MODULE_VERSION(pvefirt, 1); 256