efirt.c revision 332028
1/*- 2 * Copyright (c) 2004 Marcel Moolenaar 3 * Copyright (c) 2001 Doug Rabson 4 * Copyright (c) 2016 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * Portions of this software were developed by Konstantin Belousov 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/11/sys/dev/efidev/efirt.c 332028 2018-04-04 13:58:18Z kevans $"); 34 35#include <sys/param.h> 36#include <sys/efi.h> 37#include <sys/kernel.h> 38#include <sys/linker.h> 39#include <sys/lock.h> 40#include <sys/module.h> 41#include <sys/mutex.h> 42#include <sys/clock.h> 43#include <sys/proc.h> 44#include <sys/rwlock.h> 45#include <sys/sched.h> 46#include <sys/sysctl.h> 47#include <sys/systm.h> 48#include <sys/vmmeter.h> 49 50#include <machine/fpu.h> 51#include <machine/efi.h> 52#include <machine/metadata.h> 53#include <machine/vmparam.h> 54 55#include <vm/vm.h> 56#include <vm/pmap.h> 57#include <vm/vm_map.h> 58 59static struct efi_systbl *efi_systbl; 60static struct efi_cfgtbl *efi_cfgtbl; 61static struct efi_rt *efi_runtime; 62 63static int efi_status2err[25] = { 64 0, /* EFI_SUCCESS */ 65 ENOEXEC, /* EFI_LOAD_ERROR */ 66 EINVAL, /* EFI_INVALID_PARAMETER */ 67 ENOSYS, /* EFI_UNSUPPORTED */ 68 EMSGSIZE, /* EFI_BAD_BUFFER_SIZE */ 69 EOVERFLOW, /* EFI_BUFFER_TOO_SMALL */ 70 EBUSY, /* EFI_NOT_READY */ 71 EIO, /* EFI_DEVICE_ERROR */ 72 EROFS, /* EFI_WRITE_PROTECTED */ 73 EAGAIN, /* EFI_OUT_OF_RESOURCES */ 74 EIO, /* EFI_VOLUME_CORRUPTED */ 75 ENOSPC, /* EFI_VOLUME_FULL */ 76 ENXIO, /* EFI_NO_MEDIA */ 77 ESTALE, /* EFI_MEDIA_CHANGED */ 78 ENOENT, /* EFI_NOT_FOUND */ 79 EACCES, /* EFI_ACCESS_DENIED */ 80 ETIMEDOUT, /* EFI_NO_RESPONSE */ 81 EADDRNOTAVAIL, /* EFI_NO_MAPPING */ 82 ETIMEDOUT, /* EFI_TIMEOUT */ 83 EDOOFUS, /* EFI_NOT_STARTED */ 84 EALREADY, /* EFI_ALREADY_STARTED */ 85 ECANCELED, /* EFI_ABORTED */ 86 EPROTO, /* EFI_ICMP_ERROR */ 87 EPROTO, /* EFI_TFTP_ERROR */ 88 EPROTO /* EFI_PROTOCOL_ERROR */ 89}; 90 91static int efi_enter(void); 92static void efi_leave(void); 93 94static int 95efi_status_to_errno(efi_status status) 96{ 97 u_long code; 98 99 code = status & 0x3ffffffffffffffful; 100 return (code < nitems(efi_status2err) ? efi_status2err[code] : EDOOFUS); 101} 102 103static struct mtx efi_lock; 104 105static bool 106efi_is_in_map(struct efi_md *map, int ndesc, int descsz, vm_offset_t addr) 107{ 108 struct efi_md *p; 109 int i; 110 111 for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p, 112 descsz)) { 113 if ((p->md_attr & EFI_MD_ATTR_RT) == 0) 114 continue; 115 116 if (addr >= (uintptr_t)p->md_virt && 117 addr < (uintptr_t)p->md_virt + p->md_pages * PAGE_SIZE) 118 return (true); 119 } 120 121 return (false); 122} 123 124static int 125efi_init(void) 126{ 127 struct efi_map_header *efihdr; 128 struct efi_md *map; 129 caddr_t kmdp; 130 size_t efisz; 131 132 mtx_init(&efi_lock, "efi", NULL, MTX_DEF); 133 134 if (efi_systbl_phys == 0) { 135 if (bootverbose) 136 printf("EFI systbl not available\n"); 137 return (0); 138 } 139 efi_systbl = (struct efi_systbl *)PHYS_TO_DMAP(efi_systbl_phys); 140 if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) { 141 efi_systbl = NULL; 142 if (bootverbose) 143 printf("EFI systbl signature invalid\n"); 144 return (0); 145 } 146 efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL : 147 (struct efi_cfgtbl *)efi_systbl->st_cfgtbl; 148 if (efi_cfgtbl == NULL) { 149 if (bootverbose) 150 printf("EFI config table is not present\n"); 151 } 152 153 kmdp = preload_search_by_type("elf kernel"); 154 if (kmdp == NULL) 155 kmdp = preload_search_by_type("elf64 kernel"); 156 efihdr = (struct efi_map_header *)preload_search_info(kmdp, 157 MODINFO_METADATA | MODINFOMD_EFI_MAP); 158 if (efihdr == NULL) { 159 if (bootverbose) 160 printf("EFI map is not present\n"); 161 return (0); 162 } 163 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; 164 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 165 if (efihdr->descriptor_size == 0) 166 return (ENOMEM); 167 168 if (!efi_create_1t1_map(map, efihdr->memory_size / 169 efihdr->descriptor_size, efihdr->descriptor_size)) { 170 if (bootverbose) 171 printf("EFI cannot create runtime map\n"); 172 return (ENOMEM); 173 } 174 175 efi_runtime = (efi_systbl->st_rt == 0) ? NULL : 176 (struct efi_rt *)efi_systbl->st_rt; 177 if (efi_runtime == NULL) { 178 if (bootverbose) 179 printf("EFI runtime services table is not present\n"); 180 efi_destroy_1t1_map(); 181 return (ENXIO); 182 } 183 184 /* 185 * Some UEFI implementations have multiple implementations of the 186 * RS->GetTime function. They switch from one we can only use early 187 * in the boot process to one valid as a RunTime service only when we 188 * call RS->SetVirtualAddressMap. As this is not always the case, e.g. 189 * with an old loader.efi, check if the RS->GetTime function is within 190 * the EFI map, and fail to attach if not. 191 * 192 * We need to enter into the EFI environment as efi_runtime may point 193 * to an EFI address. 194 */ 195 efi_enter(); 196 if (!efi_is_in_map(map, efihdr->memory_size / efihdr->descriptor_size, 197 efihdr->descriptor_size, (vm_offset_t)efi_runtime->rt_gettime)) { 198 efi_leave(); 199 if (bootverbose) 200 printf( 201 "EFI runtime services table has an invalid pointer\n"); 202 efi_runtime = NULL; 203 efi_destroy_1t1_map(); 204 return (ENXIO); 205 } 206 efi_leave(); 207 208 return (0); 209} 210 211static void 212efi_uninit(void) 213{ 214 215 efi_destroy_1t1_map(); 216 217 efi_systbl = NULL; 218 efi_cfgtbl = NULL; 219 efi_runtime = NULL; 220 221 mtx_destroy(&efi_lock); 222} 223 224int 225efi_rt_ok(void) 226{ 227 228 if (efi_runtime == NULL) 229 return (ENXIO); 230 return (0); 231} 232 233static int 234efi_enter(void) 235{ 236 struct thread *td; 237 pmap_t curpmap; 238 int error; 239 240 if (efi_runtime == NULL) 241 return (ENXIO); 242 td = curthread; 243 curpmap = &td->td_proc->p_vmspace->vm_pmap; 244 PMAP_LOCK(curpmap); 245 mtx_lock(&efi_lock); 246 error = fpu_kern_enter(td, NULL, FPU_KERN_NOCTX); 247 if (error != 0) { 248 PMAP_UNLOCK(curpmap); 249 return (error); 250 } 251 252 return (efi_arch_enter()); 253} 254 255static void 256efi_leave(void) 257{ 258 struct thread *td; 259 pmap_t curpmap; 260 261 efi_arch_leave(); 262 263 curpmap = &curproc->p_vmspace->vm_pmap; 264 td = curthread; 265 fpu_kern_leave(td, NULL); 266 mtx_unlock(&efi_lock); 267 PMAP_UNLOCK(curpmap); 268} 269 270int 271efi_get_table(struct uuid *uuid, void **ptr) 272{ 273 struct efi_cfgtbl *ct; 274 u_long count; 275 276 if (efi_cfgtbl == NULL || efi_systbl == NULL) 277 return (ENXIO); 278 count = efi_systbl->st_entries; 279 ct = efi_cfgtbl; 280 while (count--) { 281 if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) { 282 *ptr = (void *)PHYS_TO_DMAP(ct->ct_data); 283 return (0); 284 } 285 ct++; 286 } 287 return (ENOENT); 288} 289 290static int 291efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap) 292{ 293 efi_status status; 294 int error; 295 296 EFI_TIME_OWNED() 297 error = efi_enter(); 298 if (error != 0) 299 return (error); 300 status = efi_runtime->rt_gettime(tm, tmcap); 301 efi_leave(); 302 error = efi_status_to_errno(status); 303 return (error); 304} 305 306int 307efi_get_time(struct efi_tm *tm) 308{ 309 struct efi_tmcap dummy; 310 int error; 311 312 if (efi_runtime == NULL) 313 return (ENXIO); 314 EFI_TIME_LOCK() 315 /* 316 * UEFI spec states that the Capabilities argument to GetTime is 317 * optional, but some UEFI implementations choke when passed a NULL 318 * pointer. Pass a dummy efi_dmcap, even though we won't use it, 319 * to workaround such implementations. 320 */ 321 error = efi_get_time_locked(tm, &dummy); 322 EFI_TIME_UNLOCK() 323 return (error); 324} 325 326int 327efi_get_time_capabilities(struct efi_tmcap *tmcap) 328{ 329 struct efi_tm dummy; 330 int error; 331 332 if (efi_runtime == NULL) 333 return (ENXIO); 334 EFI_TIME_LOCK() 335 error = efi_get_time_locked(&dummy, tmcap); 336 EFI_TIME_UNLOCK() 337 return (error); 338} 339 340int 341efi_reset_system(void) 342{ 343 int error; 344 345 error = efi_enter(); 346 if (error != 0) 347 return (error); 348 efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL); 349 efi_leave(); 350 return (EIO); 351} 352 353static int 354efi_set_time_locked(struct efi_tm *tm) 355{ 356 efi_status status; 357 int error; 358 359 EFI_TIME_OWNED(); 360 error = efi_enter(); 361 if (error != 0) 362 return (error); 363 status = efi_runtime->rt_settime(tm); 364 efi_leave(); 365 error = efi_status_to_errno(status); 366 return (error); 367} 368 369int 370efi_set_time(struct efi_tm *tm) 371{ 372 int error; 373 374 if (efi_runtime == NULL) 375 return (ENXIO); 376 EFI_TIME_LOCK() 377 error = efi_set_time_locked(tm); 378 EFI_TIME_UNLOCK() 379 return (error); 380} 381 382int 383efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, 384 size_t *datasize, void *data) 385{ 386 efi_status status; 387 int error; 388 389 error = efi_enter(); 390 if (error != 0) 391 return (error); 392 status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); 393 efi_leave(); 394 error = efi_status_to_errno(status); 395 return (error); 396} 397 398int 399efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) 400{ 401 efi_status status; 402 int error; 403 404 error = efi_enter(); 405 if (error != 0) 406 return (error); 407 status = efi_runtime->rt_scanvar(namesize, name, vendor); 408 efi_leave(); 409 error = efi_status_to_errno(status); 410 return (error); 411} 412 413int 414efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, 415 size_t datasize, void *data) 416{ 417 efi_status status; 418 int error; 419 420 error = efi_enter(); 421 if (error != 0) 422 return (error); 423 status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); 424 efi_leave(); 425 error = efi_status_to_errno(status); 426 return (error); 427} 428 429static int 430efirt_modevents(module_t m, int event, void *arg __unused) 431{ 432 433 switch (event) { 434 case MOD_LOAD: 435 return (efi_init()); 436 437 case MOD_UNLOAD: 438 efi_uninit(); 439 return (0); 440 441 case MOD_SHUTDOWN: 442 return (0); 443 444 default: 445 return (EOPNOTSUPP); 446 } 447} 448 449static moduledata_t efirt_moddata = { 450 .name = "efirt", 451 .evhand = efirt_modevents, 452 .priv = NULL, 453}; 454/* After fpuinitstate, before efidev */ 455DECLARE_MODULE(efirt, efirt_moddata, SI_SUB_DRIVERS, SI_ORDER_SECOND); 456MODULE_VERSION(efirt, 1); 457