184121Sdfr/*- 2135453Smarcel * Copyright (c) 2004 Marcel Moolenaar 384121Sdfr * Copyright (c) 2001 Doug Rabson 484121Sdfr * All rights reserved. 584121Sdfr * 684121Sdfr * Redistribution and use in source and binary forms, with or without 784121Sdfr * modification, are permitted provided that the following conditions 884121Sdfr * are met: 984121Sdfr * 1. Redistributions of source code must retain the above copyright 1084121Sdfr * notice, this list of conditions and the following disclaimer. 1184121Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1284121Sdfr * notice, this list of conditions and the following disclaimer in the 1384121Sdfr * documentation and/or other materials provided with the distribution. 1484121Sdfr * 1584121Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1684121Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1784121Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1884121Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1984121Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2084121Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2184121Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2284121Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2384121Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2484121Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2584121Sdfr * SUCH DAMAGE. 2684121Sdfr */ 2784121Sdfr 28135453Smarcel#include <sys/cdefs.h> 29135453Smarcel__FBSDID("$FreeBSD$"); 30135453Smarcel 3184121Sdfr#include <sys/param.h> 3284121Sdfr#include <sys/systm.h> 3384121Sdfr#include <machine/bootinfo.h> 3484121Sdfr#include <machine/efi.h> 35219841Smarcel#include <machine/md_var.h> 3684121Sdfr#include <machine/sal.h> 37203883Smarcel#include <vm/vm.h> 38203883Smarcel#include <vm/pmap.h> 3984121Sdfr 40135453Smarcelstatic struct efi_systbl *efi_systbl; 41135453Smarcelstatic struct efi_cfgtbl *efi_cfgtbl; 42135453Smarcelstatic struct efi_rt *efi_runtime; 4384121Sdfr 44202271Smarcelstatic int efi_status2err[25] = { 45202271Smarcel 0, /* EFI_SUCCESS */ 46202271Smarcel ENOEXEC, /* EFI_LOAD_ERROR */ 47202271Smarcel EINVAL, /* EFI_INVALID_PARAMETER */ 48202271Smarcel ENOSYS, /* EFI_UNSUPPORTED */ 49202271Smarcel EMSGSIZE, /* EFI_BAD_BUFFER_SIZE */ 50202271Smarcel EOVERFLOW, /* EFI_BUFFER_TOO_SMALL */ 51202271Smarcel EBUSY, /* EFI_NOT_READY */ 52202271Smarcel EIO, /* EFI_DEVICE_ERROR */ 53202271Smarcel EROFS, /* EFI_WRITE_PROTECTED */ 54202271Smarcel EAGAIN, /* EFI_OUT_OF_RESOURCES */ 55202271Smarcel EIO, /* EFI_VOLUME_CORRUPTED */ 56202271Smarcel ENOSPC, /* EFI_VOLUME_FULL */ 57202271Smarcel ENXIO, /* EFI_NO_MEDIA */ 58202271Smarcel ESTALE, /* EFI_MEDIA_CHANGED */ 59202271Smarcel ENOENT, /* EFI_NOT_FOUND */ 60202271Smarcel EACCES, /* EFI_ACCESS_DENIED */ 61202271Smarcel ETIMEDOUT, /* EFI_NO_RESPONSE */ 62202271Smarcel EADDRNOTAVAIL, /* EFI_NO_MAPPING */ 63202271Smarcel ETIMEDOUT, /* EFI_TIMEOUT */ 64202271Smarcel EDOOFUS, /* EFI_NOT_STARTED */ 65202271Smarcel EALREADY, /* EFI_ALREADY_STARTED */ 66202271Smarcel ECANCELED, /* EFI_ABORTED */ 67202271Smarcel EPROTO, /* EFI_ICMP_ERROR */ 68202271Smarcel EPROTO, /* EFI_TFTP_ERROR */ 69202271Smarcel EPROTO /* EFI_PROTOCOL_ERROR */ 70202271Smarcel}; 71202271Smarcel 72202271Smarcelstatic int 73202271Smarcelefi_status_to_errno(efi_status status) 74202271Smarcel{ 75202271Smarcel u_long code; 76202271Smarcel int error; 77202271Smarcel 78202271Smarcel code = status & 0x3ffffffffffffffful; 79202271Smarcel error = (code < 25) ? efi_status2err[code] : EDOOFUS; 80202271Smarcel return (error); 81202271Smarcel} 82202271Smarcel 8384121Sdfrvoid 84135453Smarcelefi_boot_finish(void) 8584121Sdfr{ 86135453Smarcel} 8784121Sdfr 88135453Smarcel/* 89135453Smarcel * Collect the entry points for PAL and SAL. Be extra careful about NULL 90135453Smarcel * pointer values. We're running pre-console, so it's better to return 91135453Smarcel * error values than to cause panics, machine checks and other traps and 92135453Smarcel * faults. Keep this minimal... 93135453Smarcel */ 94135453Smarcelint 95135453Smarcelefi_boot_minimal(uint64_t systbl) 96135453Smarcel{ 97219841Smarcel ia64_efi_f setvirt; 98135453Smarcel struct efi_md *md; 99135453Smarcel efi_status status; 100135453Smarcel 101135453Smarcel if (systbl == 0) 102135453Smarcel return (EINVAL); 103135453Smarcel efi_systbl = (struct efi_systbl *)IA64_PHYS_TO_RR7(systbl); 104135453Smarcel if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) { 105135453Smarcel efi_systbl = NULL; 106135453Smarcel return (EFAULT); 10784121Sdfr } 108135453Smarcel efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL : 109135453Smarcel (struct efi_cfgtbl *)IA64_PHYS_TO_RR7(efi_systbl->st_cfgtbl); 110135453Smarcel if (efi_cfgtbl == NULL) 111135453Smarcel return (ENOENT); 112135453Smarcel efi_runtime = (efi_systbl->st_rt == 0) ? NULL : 113135453Smarcel (struct efi_rt *)IA64_PHYS_TO_RR7(efi_systbl->st_rt); 114135453Smarcel if (efi_runtime == NULL) 115135453Smarcel return (ENOENT); 11684121Sdfr 117135453Smarcel /* 118135453Smarcel * Relocate runtime memory segments for firmware. 119135453Smarcel */ 120135453Smarcel md = efi_md_first(); 121135453Smarcel while (md != NULL) { 122135453Smarcel if (md->md_attr & EFI_MD_ATTR_RT) { 123219841Smarcel md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ? 124219841Smarcel (void *)IA64_PHYS_TO_RR7(md->md_phys) : 125219841Smarcel (void *)IA64_PHYS_TO_RR6(md->md_phys); 12684121Sdfr } 127135453Smarcel md = efi_md_next(md); 12884121Sdfr } 129219841Smarcel setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual); 130219841Smarcel status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size, 131219841Smarcel bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version, 132221271Smarcel ia64_tpa(bootinfo->bi_memmap)); 133135453Smarcel return ((status < 0) ? EFAULT : 0); 134135453Smarcel} 13584121Sdfr 136135453Smarcelvoid * 137135453Smarcelefi_get_table(struct uuid *uuid) 138135453Smarcel{ 139135453Smarcel struct efi_cfgtbl *ct; 140135453Smarcel u_long count; 14184121Sdfr 142135453Smarcel if (efi_cfgtbl == NULL) 143135453Smarcel return (NULL); 144135453Smarcel count = efi_systbl->st_entries; 145135453Smarcel ct = efi_cfgtbl; 146135453Smarcel while (count--) { 147183299Sobrien if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) 148135453Smarcel return ((void *)IA64_PHYS_TO_RR7(ct->ct_data)); 149135453Smarcel ct++; 15084121Sdfr } 151135453Smarcel return (NULL); 152135453Smarcel} 15384121Sdfr 154135453Smarcelvoid 155135453Smarcelefi_get_time(struct efi_tm *tm) 156135453Smarcel{ 15784121Sdfr 158135453Smarcel efi_runtime->rt_gettime(tm, NULL); 15984121Sdfr} 16084121Sdfr 161135453Smarcelstruct efi_md * 162135453Smarcelefi_md_first(void) 163135453Smarcel{ 164224112Smarcel struct efi_md *md; 165135453Smarcel 166219841Smarcel if (bootinfo->bi_memmap == 0) 167135453Smarcel return (NULL); 168224112Smarcel md = (struct efi_md *)bootinfo->bi_memmap; 169224112Smarcel return (md); 170135453Smarcel} 171135453Smarcel 172135453Smarcelstruct efi_md * 173224112Smarcelefi_md_last(void) 174224112Smarcel{ 175224112Smarcel struct efi_md *md; 176224112Smarcel 177224112Smarcel if (bootinfo->bi_memmap == 0) 178224112Smarcel return (NULL); 179224112Smarcel md = (struct efi_md *)(bootinfo->bi_memmap + bootinfo->bi_memmap_size - 180224112Smarcel bootinfo->bi_memdesc_size); 181224112Smarcel return (md); 182224112Smarcel} 183224112Smarcel 184224112Smarcelstruct efi_md * 185135453Smarcelefi_md_next(struct efi_md *md) 186135453Smarcel{ 187224112Smarcel struct efi_md *lim; 188135453Smarcel 189224112Smarcel lim = efi_md_last(); 190219841Smarcel md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size); 191224112Smarcel return ((md > lim) ? NULL : md); 192135453Smarcel} 193135453Smarcel 194224112Smarcelstruct efi_md * 195224112Smarcelefi_md_prev(struct efi_md *md) 196224112Smarcel{ 197224112Smarcel struct efi_md *lim; 198224112Smarcel 199224112Smarcel lim = efi_md_first(); 200224112Smarcel md = (struct efi_md *)((uintptr_t)md - bootinfo->bi_memdesc_size); 201224112Smarcel return ((md < lim) ? NULL : md); 202224112Smarcel} 203224112Smarcel 204224112Smarcelstruct efi_md * 205224112Smarcelefi_md_find(vm_paddr_t pa) 206224112Smarcel{ 207224112Smarcel static struct efi_md *last = NULL; 208224112Smarcel struct efi_md *md, *p0, *p1; 209224112Smarcel 210224112Smarcel md = (last != NULL) ? last : efi_md_first(); 211224112Smarcel p1 = p0 = NULL; 212224112Smarcel while (md != NULL && md != p1) { 213224112Smarcel if (pa >= md->md_phys && 214224112Smarcel pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) { 215224112Smarcel last = md; 216224112Smarcel return (md); 217224112Smarcel } 218224112Smarcel 219224112Smarcel p1 = p0; 220224112Smarcel p0 = md; 221224112Smarcel md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md); 222224112Smarcel } 223224112Smarcel 224224112Smarcel return (NULL); 225224112Smarcel} 226224112Smarcel 227135453Smarcelvoid 228135453Smarcelefi_reset_system(void) 229135453Smarcel{ 230135453Smarcel 231135453Smarcel if (efi_runtime != NULL) 232135453Smarcel efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL); 233135453Smarcel panic("%s: unable to reset the machine", __func__); 234135453Smarcel} 235135453Smarcel 236202271Smarcelint 237135453Smarcelefi_set_time(struct efi_tm *tm) 238135453Smarcel{ 239135453Smarcel 240202271Smarcel return (efi_status_to_errno(efi_runtime->rt_settime(tm))); 241135453Smarcel} 242202271Smarcel 243202271Smarcelint 244202271Smarcelefi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, 245202271Smarcel size_t *datasize, void *data) 246202271Smarcel{ 247202271Smarcel efi_status status; 248202271Smarcel 249202271Smarcel status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); 250202271Smarcel return (efi_status_to_errno(status)); 251202271Smarcel} 252202271Smarcel 253202271Smarcelint 254202271Smarcelefi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) 255202271Smarcel{ 256202271Smarcel efi_status status; 257202271Smarcel 258202271Smarcel status = efi_runtime->rt_scanvar(namesize, name, vendor); 259202271Smarcel return (efi_status_to_errno(status)); 260202271Smarcel} 261202271Smarcel 262202271Smarcelint 263202272Smarcelefi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, 264202272Smarcel size_t datasize, void *data) 265202271Smarcel{ 266202271Smarcel efi_status status; 267202271Smarcel 268202272Smarcel status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); 269202271Smarcel return (efi_status_to_errno(status)); 270202271Smarcel} 271