/*- * Copyright (c) 2004 Marcel Moolenaar * Copyright (c) 2001 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static struct efi_systbl *efi_systbl; static struct efi_cfgtbl *efi_cfgtbl; static struct efi_rt *efi_runtime; static int efi_status2err[25] = { 0, /* EFI_SUCCESS */ ENOEXEC, /* EFI_LOAD_ERROR */ EINVAL, /* EFI_INVALID_PARAMETER */ ENOSYS, /* EFI_UNSUPPORTED */ EMSGSIZE, /* EFI_BAD_BUFFER_SIZE */ EOVERFLOW, /* EFI_BUFFER_TOO_SMALL */ EBUSY, /* EFI_NOT_READY */ EIO, /* EFI_DEVICE_ERROR */ EROFS, /* EFI_WRITE_PROTECTED */ EAGAIN, /* EFI_OUT_OF_RESOURCES */ EIO, /* EFI_VOLUME_CORRUPTED */ ENOSPC, /* EFI_VOLUME_FULL */ ENXIO, /* EFI_NO_MEDIA */ ESTALE, /* EFI_MEDIA_CHANGED */ ENOENT, /* EFI_NOT_FOUND */ EACCES, /* EFI_ACCESS_DENIED */ ETIMEDOUT, /* EFI_NO_RESPONSE */ EADDRNOTAVAIL, /* EFI_NO_MAPPING */ ETIMEDOUT, /* EFI_TIMEOUT */ EDOOFUS, /* EFI_NOT_STARTED */ EALREADY, /* EFI_ALREADY_STARTED */ ECANCELED, /* EFI_ABORTED */ EPROTO, /* EFI_ICMP_ERROR */ EPROTO, /* EFI_TFTP_ERROR */ EPROTO /* EFI_PROTOCOL_ERROR */ }; static int efi_status_to_errno(efi_status status) { u_long code; int error; code = status & 0x3ffffffffffffffful; error = (code < 25) ? efi_status2err[code] : EDOOFUS; return (error); } void efi_boot_finish(void) { } /* * Collect the entry points for PAL and SAL. Be extra careful about NULL * pointer values. We're running pre-console, so it's better to return * error values than to cause panics, machine checks and other traps and * faults. Keep this minimal... */ int efi_boot_minimal(uint64_t systbl) { ia64_efi_f setvirt; struct efi_md *md; efi_status status; if (systbl == 0) return (EINVAL); efi_systbl = (struct efi_systbl *)IA64_PHYS_TO_RR7(systbl); if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) { efi_systbl = NULL; return (EFAULT); } efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL : (struct efi_cfgtbl *)IA64_PHYS_TO_RR7(efi_systbl->st_cfgtbl); if (efi_cfgtbl == NULL) return (ENOENT); efi_runtime = (efi_systbl->st_rt == 0) ? NULL : (struct efi_rt *)IA64_PHYS_TO_RR7(efi_systbl->st_rt); if (efi_runtime == NULL) return (ENOENT); /* * Relocate runtime memory segments for firmware. */ md = efi_md_first(); while (md != NULL) { if (md->md_attr & EFI_MD_ATTR_RT) { md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ? (void *)IA64_PHYS_TO_RR7(md->md_phys) : (void *)IA64_PHYS_TO_RR6(md->md_phys); } md = efi_md_next(md); } setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual); status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size, bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version, ia64_tpa(bootinfo->bi_memmap)); return ((status < 0) ? EFAULT : 0); } void * efi_get_table(struct uuid *uuid) { struct efi_cfgtbl *ct; u_long count; if (efi_cfgtbl == NULL) return (NULL); count = efi_systbl->st_entries; ct = efi_cfgtbl; while (count--) { if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) return ((void *)IA64_PHYS_TO_RR7(ct->ct_data)); ct++; } return (NULL); } void efi_get_time(struct efi_tm *tm) { efi_runtime->rt_gettime(tm, NULL); } struct efi_md * efi_md_first(void) { struct efi_md *md; if (bootinfo->bi_memmap == 0) return (NULL); md = (struct efi_md *)bootinfo->bi_memmap; return (md); } struct efi_md * efi_md_last(void) { struct efi_md *md; if (bootinfo->bi_memmap == 0) return (NULL); md = (struct efi_md *)(bootinfo->bi_memmap + bootinfo->bi_memmap_size - bootinfo->bi_memdesc_size); return (md); } struct efi_md * efi_md_next(struct efi_md *md) { struct efi_md *lim; lim = efi_md_last(); md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size); return ((md > lim) ? NULL : md); } struct efi_md * efi_md_prev(struct efi_md *md) { struct efi_md *lim; lim = efi_md_first(); md = (struct efi_md *)((uintptr_t)md - bootinfo->bi_memdesc_size); return ((md < lim) ? NULL : md); } struct efi_md * efi_md_find(vm_paddr_t pa) { static struct efi_md *last = NULL; struct efi_md *md, *p0, *p1; md = (last != NULL) ? last : efi_md_first(); p1 = p0 = NULL; while (md != NULL && md != p1) { if (pa >= md->md_phys && pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) { last = md; return (md); } p1 = p0; p0 = md; md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md); } return (NULL); } void efi_reset_system(void) { if (efi_runtime != NULL) efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL); panic("%s: unable to reset the machine", __func__); } int efi_set_time(struct efi_tm *tm) { return (efi_status_to_errno(efi_runtime->rt_settime(tm))); } int efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, size_t *datasize, void *data) { efi_status status; status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); return (efi_status_to_errno(status)); } int efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) { efi_status status; status = efi_runtime->rt_scanvar(namesize, name, vendor); return (efi_status_to_errno(status)); } int efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, size_t datasize, void *data) { efi_status status; status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); return (efi_status_to_errno(status)); }