1/*- 2 * Copyright (c) 2004 Marcel Moolenaar 3 * Copyright (c) 2001 Doug Rabson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD$"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <machine/bootinfo.h> 34#include <machine/efi.h> 35#include <machine/md_var.h> 36#include <machine/sal.h> 37#include <vm/vm.h> 38#include <vm/pmap.h> 39 40static struct efi_systbl *efi_systbl; 41static struct efi_cfgtbl *efi_cfgtbl; 42static struct efi_rt *efi_runtime; 43 44static int efi_status2err[25] = { 45 0, /* EFI_SUCCESS */ 46 ENOEXEC, /* EFI_LOAD_ERROR */ 47 EINVAL, /* EFI_INVALID_PARAMETER */ 48 ENOSYS, /* EFI_UNSUPPORTED */ 49 EMSGSIZE, /* EFI_BAD_BUFFER_SIZE */ 50 EOVERFLOW, /* EFI_BUFFER_TOO_SMALL */ 51 EBUSY, /* EFI_NOT_READY */ 52 EIO, /* EFI_DEVICE_ERROR */ 53 EROFS, /* EFI_WRITE_PROTECTED */ 54 EAGAIN, /* EFI_OUT_OF_RESOURCES */ 55 EIO, /* EFI_VOLUME_CORRUPTED */ 56 ENOSPC, /* EFI_VOLUME_FULL */ 57 ENXIO, /* EFI_NO_MEDIA */ 58 ESTALE, /* EFI_MEDIA_CHANGED */ 59 ENOENT, /* EFI_NOT_FOUND */ 60 EACCES, /* EFI_ACCESS_DENIED */ 61 ETIMEDOUT, /* EFI_NO_RESPONSE */ 62 EADDRNOTAVAIL, /* EFI_NO_MAPPING */ 63 ETIMEDOUT, /* EFI_TIMEOUT */ 64 EDOOFUS, /* EFI_NOT_STARTED */ 65 EALREADY, /* EFI_ALREADY_STARTED */ 66 ECANCELED, /* EFI_ABORTED */ 67 EPROTO, /* EFI_ICMP_ERROR */ 68 EPROTO, /* EFI_TFTP_ERROR */ 69 EPROTO /* EFI_PROTOCOL_ERROR */ 70}; 71 72static int 73efi_status_to_errno(efi_status status) 74{ 75 u_long code; 76 int error; 77 78 code = status & 0x3ffffffffffffffful; 79 error = (code < 25) ? efi_status2err[code] : EDOOFUS; 80 return (error); 81} 82 83void 84efi_boot_finish(void) 85{ 86} 87 88/* 89 * Collect the entry points for PAL and SAL. Be extra careful about NULL 90 * pointer values. We're running pre-console, so it's better to return 91 * error values than to cause panics, machine checks and other traps and 92 * faults. Keep this minimal... 93 */ 94int 95efi_boot_minimal(uint64_t systbl) 96{ 97 ia64_efi_f setvirt; 98 struct efi_md *md; 99 efi_status status; 100 101 if (systbl == 0) 102 return (EINVAL); 103 efi_systbl = (struct efi_systbl *)IA64_PHYS_TO_RR7(systbl); 104 if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) { 105 efi_systbl = NULL; 106 return (EFAULT); 107 } 108 efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL : 109 (struct efi_cfgtbl *)IA64_PHYS_TO_RR7(efi_systbl->st_cfgtbl); 110 if (efi_cfgtbl == NULL) 111 return (ENOENT); 112 efi_runtime = (efi_systbl->st_rt == 0) ? NULL : 113 (struct efi_rt *)IA64_PHYS_TO_RR7(efi_systbl->st_rt); 114 if (efi_runtime == NULL) 115 return (ENOENT); 116 117 /* 118 * Relocate runtime memory segments for firmware. 119 */ 120 md = efi_md_first(); 121 while (md != NULL) { 122 if (md->md_attr & EFI_MD_ATTR_RT) { 123 md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ? 124 (void *)IA64_PHYS_TO_RR7(md->md_phys) : 125 (void *)IA64_PHYS_TO_RR6(md->md_phys); 126 } 127 md = efi_md_next(md); 128 } 129 setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual); 130 status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size, 131 bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version, 132 ia64_tpa(bootinfo->bi_memmap)); 133 return ((status < 0) ? EFAULT : 0); 134} 135 136void * 137efi_get_table(struct uuid *uuid) 138{ 139 struct efi_cfgtbl *ct; 140 u_long count; 141 142 if (efi_cfgtbl == NULL) 143 return (NULL); 144 count = efi_systbl->st_entries; 145 ct = efi_cfgtbl; 146 while (count--) { 147 if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) 148 return ((void *)IA64_PHYS_TO_RR7(ct->ct_data)); 149 ct++; 150 } 151 return (NULL); 152} 153 154void 155efi_get_time(struct efi_tm *tm) 156{ 157 158 efi_runtime->rt_gettime(tm, NULL); 159} 160 161struct efi_md * 162efi_md_first(void) 163{ 164 struct efi_md *md; 165 166 if (bootinfo->bi_memmap == 0) 167 return (NULL); 168 md = (struct efi_md *)bootinfo->bi_memmap; 169 return (md); 170} 171 172struct efi_md * 173efi_md_last(void) 174{ 175 struct efi_md *md; 176 177 if (bootinfo->bi_memmap == 0) 178 return (NULL); 179 md = (struct efi_md *)(bootinfo->bi_memmap + bootinfo->bi_memmap_size - 180 bootinfo->bi_memdesc_size); 181 return (md); 182} 183 184struct efi_md * 185efi_md_next(struct efi_md *md) 186{ 187 struct efi_md *lim; 188 189 lim = efi_md_last(); 190 md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size); 191 return ((md > lim) ? NULL : md); 192} 193 194struct efi_md * 195efi_md_prev(struct efi_md *md) 196{ 197 struct efi_md *lim; 198 199 lim = efi_md_first(); 200 md = (struct efi_md *)((uintptr_t)md - bootinfo->bi_memdesc_size); 201 return ((md < lim) ? NULL : md); 202} 203 204struct efi_md * 205efi_md_find(vm_paddr_t pa) 206{ 207 static struct efi_md *last = NULL; 208 struct efi_md *md, *p0, *p1; 209 210 md = (last != NULL) ? last : efi_md_first(); 211 p1 = p0 = NULL; 212 while (md != NULL && md != p1) { 213 if (pa >= md->md_phys && 214 pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) { 215 last = md; 216 return (md); 217 } 218 219 p1 = p0; 220 p0 = md; 221 md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md); 222 } 223 224 return (NULL); 225} 226 227void 228efi_reset_system(void) 229{ 230 231 if (efi_runtime != NULL) 232 efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL); 233 panic("%s: unable to reset the machine", __func__); 234} 235 236int 237efi_set_time(struct efi_tm *tm) 238{ 239 240 return (efi_status_to_errno(efi_runtime->rt_settime(tm))); 241} 242 243int 244efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, 245 size_t *datasize, void *data) 246{ 247 efi_status status; 248 249 status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); 250 return (efi_status_to_errno(status)); 251} 252 253int 254efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) 255{ 256 efi_status status; 257 258 status = efi_runtime->rt_scanvar(namesize, name, vendor); 259 return (efi_status_to_errno(status)); 260} 261 262int 263efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, 264 size_t datasize, void *data) 265{ 266 efi_status status; 267 268 status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); 269 return (efi_status_to_errno(status)); 270} 271