Index: stable/11/stand/common/bootstrap.h =================================================================== --- stable/11/stand/common/bootstrap.h (revision 344289) +++ stable/11/stand/common/bootstrap.h (revision 344290) @@ -1,338 +1,343 @@ /*- * Copyright (c) 1998 Michael Smith * 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. * * $FreeBSD$ */ #ifndef _BOOTSTRAP_H_ #define _BOOTSTRAP_H_ #include #include #include /* Commands and return values; nonzero return sets command_errmsg != NULL */ typedef int (bootblk_cmd_t)(int argc, char *argv[]); #define COMMAND_ERRBUFSZ (256) extern const char *command_errmsg; extern char command_errbuf[COMMAND_ERRBUFSZ]; #define CMD_OK 0 #define CMD_WARN 1 #define CMD_ERROR 2 #define CMD_CRIT 3 #define CMD_FATAL 4 /* interp.c */ void interact(void); void interp_emit_prompt(void); int interp_builtin_cmd(int argc, char *argv[]); /* Called by interp.c for interp_*.c embedded interpreters */ int interp_include(const char *filename); /* Execute commands from filename */ void interp_init(void); /* Initialize interpreater */ int interp_run(const char *line); /* Run a single command */ /* interp_backslash.c */ char *backslash(const char *str); /* interp_parse.c */ int parse(int *argc, char ***argv, const char *str); /* boot.c */ void autoboot_maybe(void); int getrootmount(char *rootdev); int bootenv_flags(void); void bootenv_set(int); /* misc.c */ char *unargv(int argc, char *argv[]); void hexdump(caddr_t region, size_t len); size_t strlenout(vm_offset_t str); char *strdupout(vm_offset_t str); void kern_bzero(vm_offset_t dest, size_t len); int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off); void *alloc_pread(int fd, off_t off, size_t len); /* bcache.c */ void bcache_init(size_t nblks, size_t bsize); void bcache_add_dev(int); void *bcache_allocate(void); void bcache_free(void *); int bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize); /* * Disk block cache */ struct bcache_devdata { int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize); void *dv_devdata; void *dv_cache; }; /* * Modular console support. */ struct console { const char *c_name; const char *c_desc; int c_flags; #define C_PRESENTIN (1<<0) /* console can provide input */ #define C_PRESENTOUT (1<<1) /* console can provide output */ #define C_ACTIVEIN (1<<2) /* user wants input from console */ #define C_ACTIVEOUT (1<<3) /* user wants output to console */ #define C_WIDEOUT (1<<4) /* c_out routine groks wide chars */ void (* c_probe)(struct console *cp); /* set c_flags to match hardware */ int (* c_init)(int arg); /* reinit XXX may need more args */ void (* c_out)(int c); /* emit c */ int (* c_in)(void); /* wait for and return input */ int (* c_ready)(void); /* return nonzer if input waiting */ }; extern struct console *consoles[]; void cons_probe(void); /* * Plug-and-play enumerator/configurator interface. */ struct pnphandler { const char *pp_name; /* handler/bus name */ void (* pp_enumerate)(void); /* enumerate PnP devices, add to chain */ }; struct pnpident { char *id_ident; /* ASCII identifier, actual format varies with bus/handler */ STAILQ_ENTRY(pnpident) id_link; }; struct pnpinfo { char *pi_desc; /* ASCII description, optional */ int pi_revision; /* optional revision (or -1) if not supported */ char *pi_module; /* module/args nominated to handle device */ int pi_argc; /* module arguments */ char **pi_argv; struct pnphandler *pi_handler; /* handler which detected this device */ STAILQ_HEAD(,pnpident) pi_ident; /* list of identifiers */ STAILQ_ENTRY(pnpinfo) pi_link; }; STAILQ_HEAD(pnpinfo_stql, pnpinfo); extern struct pnphandler *pnphandlers[]; /* provided by MD code */ void pnp_addident(struct pnpinfo *pi, char *ident); struct pnpinfo *pnp_allocinfo(void); void pnp_freeinfo(struct pnpinfo *pi); void pnp_addinfo(struct pnpinfo *pi); char *pnp_eisaformat(uint8_t *data); /* * < 0 - No ISA in system * == 0 - Maybe ISA, search for read data port * > 0 - ISA in system, value is read data port address */ extern int isapnp_readport; /* + * Version information + */ +extern char bootprog_info[]; + +/* * Preloaded file metadata header. * * Metadata are allocated on our heap, and copied into kernel space * before executing the kernel. */ struct file_metadata { size_t md_size; uint16_t md_type; struct file_metadata *md_next; char md_data[1]; /* data are immediately appended */ }; struct preloaded_file; struct mod_depend; struct kernel_module { char *m_name; /* module name */ int m_version; /* module version */ /* char *m_args;*/ /* arguments for the module */ struct preloaded_file *m_fp; struct kernel_module *m_next; }; /* * Preloaded file information. Depending on type, file can contain * additional units called 'modules'. * * At least one file (the kernel) must be loaded in order to boot. * The kernel is always loaded first. * * String fields (m_name, m_type) should be dynamically allocated. */ struct preloaded_file { char *f_name; /* file name */ char *f_type; /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */ char *f_args; /* arguments for the file */ struct file_metadata *f_metadata; /* metadata that will be placed in the module directory */ int f_loader; /* index of the loader that read the file */ vm_offset_t f_addr; /* load address */ size_t f_size; /* file size */ struct kernel_module *f_modules; /* list of modules if any */ struct preloaded_file *f_next; /* next file */ }; struct file_format { /* Load function must return EFTYPE if it can't handle the module supplied */ int (* l_load)(char *filename, uint64_t dest, struct preloaded_file **result); /* Only a loader that will load a kernel (first module) should have an exec handler */ int (* l_exec)(struct preloaded_file *mp); }; extern struct file_format *file_formats[]; /* supplied by consumer */ extern struct preloaded_file *preloaded_files; int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]); int mod_loadkld(const char *name, int argc, char *argv[]); void unload(void); struct preloaded_file *file_alloc(void); struct preloaded_file *file_findfile(const char *name, const char *type); struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type); struct preloaded_file *file_loadraw(const char *name, char *type, int insert); void file_discard(struct preloaded_file *fp); void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p); int file_addmodule(struct preloaded_file *fp, char *modname, int version, struct kernel_module **newmp); void file_removemetadata(struct preloaded_file *fp); /* MI module loaders */ #ifdef __elfN /* Relocation types. */ #define ELF_RELOC_REL 1 #define ELF_RELOC_RELA 2 /* Relocation offset for some architectures */ extern uint64_t __elfN(relocation_offset); struct elf_file; typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx); int __elfN(loadfile)(char *filename, uint64_t dest, struct preloaded_file **result); int __elfN(obj_loadfile)(char *filename, uint64_t dest, struct preloaded_file **result); int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len); int __elfN(loadfile_raw)(char *filename, uint64_t dest, struct preloaded_file **result, int multiboot); int __elfN(load_modmetadata)(struct preloaded_file *fp, uint64_t dest); #endif /* * Support for commands */ struct bootblk_command { const char *c_name; const char *c_desc; bootblk_cmd_t *c_fn; }; #define COMMAND_SET(tag, key, desc, func) \ static bootblk_cmd_t func; \ static struct bootblk_command _cmd_ ## tag = { key, desc, func }; \ DATA_SET(Xcommand_set, _cmd_ ## tag) SET_DECLARE(Xcommand_set, struct bootblk_command); /* * The intention of the architecture switch is to provide a convenient * encapsulation of the interface between the bootstrap MI and MD code. * MD code may selectively populate the switch at runtime based on the * actual configuration of the target system. */ struct arch_switch { /* Automatically load modules as required by detected hardware */ int (*arch_autoload)(void); /* Locate the device for (name), return pointer to tail in (*path) */ int (*arch_getdev)(void **dev, const char *name, const char **path); /* Copy from local address space to module address space, similar to bcopy() */ ssize_t (*arch_copyin)(const void *src, vm_offset_t dest, const size_t len); /* Copy to local address space from module address space, similar to bcopy() */ ssize_t (*arch_copyout)(const vm_offset_t src, void *dest, const size_t len); /* Read from file to module address space, same semantics as read() */ ssize_t (*arch_readin)(const int fd, vm_offset_t dest, const size_t len); /* Perform ISA byte port I/O (only for systems with ISA) */ int (*arch_isainb)(int port); void (*arch_isaoutb)(int port, int value); /* * Interface to adjust the load address according to the "object" * being loaded. */ uint64_t (*arch_loadaddr)(u_int type, void *data, uint64_t addr); #define LOAD_ELF 1 /* data points to the ELF header. */ #define LOAD_RAW 2 /* data points to the file name. */ /* * Interface to inform MD code about a loaded (ELF) segment. This * can be used to flush caches and/or set up translations. */ #ifdef __elfN void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta); #else void (*arch_loadseg)(void *eh, void *ph, uint64_t delta); #endif /* Probe ZFS pool(s), if needed. */ void (*arch_zfs_probe)(void); /* For kexec-type loaders, get ksegment structure */ void (*arch_kexec_kseg_get)(int *nseg, void **kseg); }; extern struct arch_switch archsw; /* This must be provided by the MD code, but should it be in the archsw? */ void delay(int delay); void dev_cleanup(void); time_t time(time_t *tloc); #ifndef CTASSERT #define CTASSERT(x) _Static_assert(x, "compile-time assertion failed") #endif #endif /* !_BOOTSTRAP_H_ */ Index: stable/11/stand/efi/loader/main.c =================================================================== --- stable/11/stand/efi/loader/main.c (revision 344289) +++ stable/11/stand/efi/loader/main.c (revision 344290) @@ -1,1054 +1,1052 @@ /*- * Copyright (c) 2008-2010 Rui Paulo * Copyright (c) 2006 Marcel Moolenaar * 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 ``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 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 #include #include #include #include #include #ifdef EFI_ZFS_BOOT #include #include "efizfs.h" #endif #include "loader_efi.h" -extern char bootprog_info[]; - struct arch_switch archsw; /* MI/MD interface boundary */ EFI_GUID acpi = ACPI_TABLE_GUID; EFI_GUID acpi20 = ACPI_20_TABLE_GUID; EFI_GUID devid = DEVICE_PATH_PROTOCOL; EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; EFI_GUID mps = MPS_TABLE_GUID; EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; EFI_GUID smbios = SMBIOS_TABLE_GUID; EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; EFI_GUID hoblist = HOB_LIST_TABLE_GUID; EFI_GUID lzmadecomp = LZMA_DECOMPRESSION_GUID; EFI_GUID mpcore = ARM_MP_CORE_INFO_TABLE_GUID; EFI_GUID esrt = ESRT_TABLE_GUID; EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; EFI_GUID fdtdtb = FDT_TABLE_GUID; EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; static EFI_LOADED_IMAGE *img; /* * Number of seconds to wait for a keystroke before exiting with failure * in the event no currdev is found. -2 means always break, -1 means * never break, 0 means poll once and then reboot, > 0 means wait for * that many seconds. "fail_timeout" can be set in the environment as * well. */ static int fail_timeout = 5; #ifdef EFI_ZFS_BOOT bool efi_zfs_is_preferred(EFI_HANDLE *h) { return (h == img->DeviceHandle); } #endif static int has_keyboard(void) { EFI_STATUS status; EFI_DEVICE_PATH *path; EFI_HANDLE *hin, *hin_end, *walker; UINTN sz; int retval = 0; /* * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and * do the typical dance to get the right sized buffer. */ sz = 0; hin = NULL; status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); if (status == EFI_BUFFER_TOO_SMALL) { hin = (EFI_HANDLE *)malloc(sz); status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, hin); if (EFI_ERROR(status)) free(hin); } if (EFI_ERROR(status)) return retval; /* * Look at each of the handles. If it supports the device path protocol, * use it to get the device path for this handle. Then see if that * device path matches either the USB device path for keyboards or the * legacy device path for keyboards. */ hin_end = &hin[sz / sizeof(*hin)]; for (walker = hin; walker < hin_end; walker++) { status = BS->HandleProtocol(*walker, &devid, (VOID **)&path); if (EFI_ERROR(status)) continue; while (!IsDevicePathEnd(path)) { /* * Check for the ACPI keyboard node. All PNP3xx nodes * are keyboards of different flavors. Note: It is * unclear of there's always a keyboard node when * there's a keyboard controller, or if there's only one * when a keyboard is detected at boot. */ if (DevicePathType(path) == ACPI_DEVICE_PATH && (DevicePathSubType(path) == ACPI_DP || DevicePathSubType(path) == ACPI_EXTENDED_DP)) { ACPI_HID_DEVICE_PATH *acpi; acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 && (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { retval = 1; goto out; } /* * Check for USB keyboard node, if present. Unlike a * PS/2 keyboard, these definitely only appear when * connected to the system. */ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && DevicePathSubType(path) == MSG_USB_CLASS_DP) { USB_CLASS_DEVICE_PATH *usb; usb = (USB_CLASS_DEVICE_PATH *)(void *)path; if (usb->DeviceClass == 3 && /* HID */ usb->DeviceSubClass == 1 && /* Boot devices */ usb->DeviceProtocol == 1) { /* Boot keyboards */ retval = 1; goto out; } } path = NextDevicePathNode(path); } } out: free(hin); return retval; } static void set_currdev_devdesc(struct devdesc *currdev) { const char *devname; devname = efi_fmtdev(currdev); printf("Setting currdev to %s\n", devname); env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset); } static void set_currdev_devsw(struct devsw *dev, int unit) { struct devdesc currdev; currdev.d_dev = dev; currdev.d_unit = unit; set_currdev_devdesc(&currdev); } static void set_currdev_pdinfo(pdinfo_t *dp) { /* * Disks are special: they have partitions. if the parent * pointer is non-null, we're a partition not a full disk * and we need to adjust currdev appropriately. */ if (dp->pd_devsw->dv_type == DEVT_DISK) { struct disk_devdesc currdev; currdev.dd.d_dev = dp->pd_devsw; if (dp->pd_parent == NULL) { currdev.dd.d_unit = dp->pd_unit; currdev.d_slice = -1; currdev.d_partition = -1; } else { currdev.dd.d_unit = dp->pd_parent->pd_unit; currdev.d_slice = dp->pd_unit; currdev.d_partition = 255; /* Assumes GPT */ } set_currdev_devdesc((struct devdesc *)&currdev); } else { set_currdev_devsw(dp->pd_devsw, dp->pd_unit); } } static bool sanity_check_currdev(void) { struct stat st; return (stat("/boot/defaults/loader.conf", &st) == 0); } #ifdef EFI_ZFS_BOOT static bool probe_zfs_currdev(uint64_t guid) { char *devname; struct zfs_devdesc currdev; currdev.dd.d_dev = &zfs_dev; currdev.dd.d_unit = 0; currdev.pool_guid = guid; currdev.root_guid = 0; set_currdev_devdesc((struct devdesc *)&currdev); devname = efi_fmtdev(&currdev); init_zfs_bootenv(devname); return (sanity_check_currdev()); } #endif static bool try_as_currdev(pdinfo_t *hd, pdinfo_t *pp) { uint64_t guid; #ifdef EFI_ZFS_BOOT /* * If there's a zpool on this device, try it as a ZFS * filesystem, which has somewhat different setup than all * other types of fs due to imperfect loader integration. * This all stems from ZFS being both a device (zpool) and * a filesystem, plus the boot env feature. */ if (efizfs_get_guid_by_handle(pp->pd_handle, &guid)) return (probe_zfs_currdev(guid)); #endif /* * All other filesystems just need the pdinfo * initialized in the standard way. */ set_currdev_pdinfo(pp); return (sanity_check_currdev()); } static int find_currdev(EFI_LOADED_IMAGE *img) { pdinfo_t *dp, *pp; EFI_DEVICE_PATH *devpath, *copy; EFI_HANDLE h; CHAR16 *text; struct devsw *dev; int unit; uint64_t extra; #ifdef EFI_ZFS_BOOT /* * Did efi_zfs_probe() detect the boot pool? If so, use the zpool * it found, if it's sane. ZFS is the only thing that looks for * disks and pools to boot. This may change in the future, however, * if we allow specifying which pool to boot from via UEFI variables * rather than the bootenv stuff that FreeBSD uses today. */ if (pool_guid != 0) { printf("Trying ZFS pool\n"); if (probe_zfs_currdev(pool_guid)) return (0); } #endif /* EFI_ZFS_BOOT */ /* * Try to find the block device by its handle based on the * image we're booting. If we can't find a sane partition, * search all the other partitions of the disk. We do not * search other disks because it's a violation of the UEFI * boot protocol to do so. We fail and let UEFI go on to * the next candidate. */ dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle); if (dp != NULL) { text = efi_devpath_name(dp->pd_devpath); if (text != NULL) { printf("Trying ESP: %S\n", text); efi_free_devpath_name(text); } set_currdev_pdinfo(dp); if (sanity_check_currdev()) return (0); if (dp->pd_parent != NULL) { dp = dp->pd_parent; STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { text = efi_devpath_name(pp->pd_devpath); if (text != NULL) { printf("And now the part: %S\n", text); efi_free_devpath_name(text); } /* * Roll up the ZFS special case * for those partitions that have * zpools on them */ if (try_as_currdev(dp, pp)) return (0); } } } else { printf("Can't find device by handle\n"); } /* * Try the device handle from our loaded image first. If that * fails, use the device path from the loaded image and see if * any of the nodes in that path match one of the enumerated * handles. Currently, this handle list is only for netboot. */ if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { set_currdev_devsw(dev, unit); if (sanity_check_currdev()) return (0); } copy = NULL; devpath = efi_lookup_image_devpath(IH); while (devpath != NULL) { h = efi_devpath_handle(devpath); if (h == NULL) break; free(copy); copy = NULL; if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { set_currdev_devsw(dev, unit); if (sanity_check_currdev()) return (0); } devpath = efi_lookup_devpath(h); if (devpath != NULL) { copy = efi_devpath_trim(devpath); devpath = copy; } } free(copy); return (ENOENT); } static bool interactive_interrupt(const char *msg) { time_t now, then, last; last = 0; now = then = getsecs(); printf("%s\n", msg); if (fail_timeout == -2) /* Always break to OK */ return (true); if (fail_timeout == -1) /* Never break to OK */ return (false); do { if (last != now) { printf("press any key to interrupt reboot in %d seconds\r", fail_timeout - (int)(now - then)); last = now; } /* XXX no pause or timeout wait for char */ if (ischar()) return (true); now = getsecs(); } while (now - then < fail_timeout); return (false); } EFI_STATUS main(int argc, CHAR16 *argv[]) { char var[128]; EFI_GUID *guid; int i, j, howto; bool vargood; UINTN k; int has_kbd; char *s; EFI_DEVICE_PATH *imgpath; CHAR16 *text; EFI_STATUS status; UINT16 boot_current; size_t sz; UINT16 boot_order[100]; #if !defined(__arm__) char buf[40]; #endif archsw.arch_autoload = efi_autoload; archsw.arch_getdev = efi_getdev; archsw.arch_copyin = efi_copyin; archsw.arch_copyout = efi_copyout; archsw.arch_readin = efi_readin; #ifdef EFI_ZFS_BOOT /* Note this needs to be set before ZFS init. */ archsw.arch_zfs_probe = efi_zfs_probe; #endif /* Get our loaded image protocol interface structure. */ BS->HandleProtocol(IH, &imgid, (VOID**)&img); /* Init the time source */ efi_time_init(); has_kbd = has_keyboard(); /* * XXX Chicken-and-egg problem; we want to have console output * early, but some console attributes may depend on reading from * eg. the boot device, which we can't do yet. We can use * printf() etc. once this is done. */ cons_probe(); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Parse the args to set the console settings, etc * boot1.efi passes these in, if it can read /boot.config or /boot/config * or iPXE may be setup to pass these in. Or the optional argument in the * boot environment was used to pass these arguments in (in which case * neither /boot.config nor /boot/config are consulted). * * Loop through the args, and for each one that contains an '=' that is * not the first character, add it to the environment. This allows * loader and kernel env vars to be passed on the command line. Convert * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this * method is flawed for non-ASCII characters). */ howto = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; argv[i][j] != 0; j++) { int ch; ch = argv[i][j]; switch (ch) { case 'a': howto |= RB_ASKNAME; break; case 'd': howto |= RB_KDB; break; case 'D': howto |= RB_MULTIPLE; break; case 'h': howto |= RB_SERIAL; break; case 'm': howto |= RB_MUTE; break; case 'p': howto |= RB_PAUSE; break; case 'P': if (!has_kbd) howto |= RB_SERIAL | RB_MULTIPLE; break; case 'r': howto |= RB_DFLTROOT; break; case 's': howto |= RB_SINGLE; break; case 'S': if (argv[i][j + 1] == 0) { if (i + 1 == argc) { setenv("comconsole_speed", "115200", 1); } else { cpy16to8(&argv[i + 1][0], var, sizeof(var)); setenv("comconsole_speed", var, 1); } i++; break; } else { cpy16to8(&argv[i][j + 1], var, sizeof(var)); setenv("comconsole_speed", var, 1); break; } case 'v': howto |= RB_VERBOSE; break; } } } else { vargood = false; for (j = 0; argv[i][j] != 0; j++) { if (j == sizeof(var)) { vargood = false; break; } if (j > 0 && argv[i][j] == '=') vargood = true; var[j] = (char)argv[i][j]; } if (vargood) { var[j] = 0; putenv(var); } } } bootenv_set(howto); /* * XXX we need fallback to this stuff after looking at the ConIn, ConOut and ConErr variables */ if (howto & RB_MULTIPLE) { if (howto & RB_SERIAL) setenv("console", "comconsole efi" , 1); else setenv("console", "efi comconsole" , 1); } else if (howto & RB_SERIAL) { setenv("console", "comconsole" , 1); } else setenv("console", "efi", 1); if (efi_copy_init()) { printf("failed to allocate staging area\n"); return (EFI_BUFFER_TOO_SMALL); } if ((s = getenv("fail_timeout")) != NULL) fail_timeout = strtol(s, NULL, 10); /* * Scan the BLOCK IO MEDIA handles then * march through the device switch probing for things. */ if ((i = efipart_inithandles()) == 0) { for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); } else printf("efipart_inithandles failed %d, expect failures", i); printf("Command line arguments:"); for (i = 0; i < argc; i++) printf(" %S", argv[i]); printf("\n"); printf("Image base: 0x%lx\n", (u_long)img->ImageBase); printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); printf("\n%s", bootprog_info); /* Determine the devpath of our image so we can prefer it. */ text = efi_devpath_name(img->FilePath); if (text != NULL) { printf(" Load Path: %S\n", text); efi_setenv_freebsd_wcs("LoaderPath", text); efi_free_devpath_name(text); } status = BS->HandleProtocol(img->DeviceHandle, &devid, (void **)&imgpath); if (status == EFI_SUCCESS) { text = efi_devpath_name(imgpath); if (text != NULL) { printf(" Load Device: %S\n", text); efi_setenv_freebsd_wcs("LoaderDev", text); efi_free_devpath_name(text); } } boot_current = 0; sz = sizeof(boot_current); efi_global_getenv("BootCurrent", &boot_current, &sz); printf(" BootCurrent: %04x\n", boot_current); sz = sizeof(boot_order); efi_global_getenv("BootOrder", &boot_order, &sz); printf(" BootOrder:"); for (i = 0; i < sz / sizeof(boot_order[0]); i++) printf(" %04x%s", boot_order[i], boot_order[i] == boot_current ? "[*]" : ""); printf("\n"); /* * Disable the watchdog timer. By default the boot manager sets * the timer to 5 minutes before invoking a boot option. If we * want to return to the boot manager, we have to disable the * watchdog timer and since we're an interactive program, we don't * want to wait until the user types "quit". The timer may have * fired by then. We don't care if this fails. It does not prevent * normal functioning in any way... */ BS->SetWatchdogTimer(0, 0, 0, NULL); /* * Try and find a good currdev based on the image that was booted. * It might be desirable here to have a short pause to allow falling * through to the boot loader instead of returning instantly to follow * the boot protocol and also allow an escape hatch for users wishing * to try something different. */ if (find_currdev(img) != 0) if (!interactive_interrupt("Failed to find bootable partition")) return (EFI_NOT_FOUND); efi_init_environment(); setenv("LINES", "24", 1); /* optional */ for (k = 0; k < ST->NumberOfTableEntries; k++) { guid = &ST->ConfigurationTable[k].VendorGuid; #if !defined(__arm__) if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { snprintf(buf, sizeof(buf), "%p", ST->ConfigurationTable[k].VendorTable); setenv("hint.smbios.0.mem", buf, 1); smbios_detect(ST->ConfigurationTable[k].VendorTable); break; } #endif } interact(); /* doesn't return */ return (EFI_SUCCESS); /* keep compiler happy */ } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); /* NOTREACHED */ return (CMD_ERROR); } COMMAND_SET(quit, "quit", "exit the loader", command_quit); static int command_quit(int argc, char *argv[]) { exit(0); return (CMD_OK); } COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); static int command_memmap(int argc, char *argv[]) { UINTN sz; EFI_MEMORY_DESCRIPTOR *map, *p; UINTN key, dsz; UINT32 dver; EFI_STATUS status; int i, ndesc; char line[80]; static char *types[] = { "Reserved", "LoaderCode", "LoaderData", "BootServicesCode", "BootServicesData", "RuntimeServicesCode", "RuntimeServicesData", "ConventionalMemory", "UnusableMemory", "ACPIReclaimMemory", "ACPIMemoryNVS", "MemoryMappedIO", "MemoryMappedIOPortSpace", "PalCode" }; sz = 0; status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); if (status != EFI_BUFFER_TOO_SMALL) { printf("Can't determine memory map size\n"); return (CMD_ERROR); } map = malloc(sz); status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); if (EFI_ERROR(status)) { printf("Can't read memory map\n"); return (CMD_ERROR); } ndesc = sz / dsz; snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n", "Type", "Physical", "Virtual", "#Pages", "Attr"); pager_open(); if (pager_output(line)) { pager_close(); return (CMD_OK); } for (i = 0, p = map; i < ndesc; i++, p = NextMemoryDescriptor(p, dsz)) { printf("%23s %012jx %012jx %08jx ", types[p->Type], (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart, (uintmax_t)p->NumberOfPages); if (p->Attribute & EFI_MEMORY_UC) printf("UC "); if (p->Attribute & EFI_MEMORY_WC) printf("WC "); if (p->Attribute & EFI_MEMORY_WT) printf("WT "); if (p->Attribute & EFI_MEMORY_WB) printf("WB "); if (p->Attribute & EFI_MEMORY_UCE) printf("UCE "); if (p->Attribute & EFI_MEMORY_WP) printf("WP "); if (p->Attribute & EFI_MEMORY_RP) printf("RP "); if (p->Attribute & EFI_MEMORY_XP) printf("XP "); if (pager_output("\n")) break; } pager_close(); return (CMD_OK); } COMMAND_SET(configuration, "configuration", "print configuration tables", command_configuration); static const char * guid_to_string(EFI_GUID *guid) { static char buf[40]; sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); return (buf); } static int command_configuration(int argc, char *argv[]) { char line[80]; UINTN i; snprintf(line, sizeof(line), "NumberOfTableEntries=%lu\n", (unsigned long)ST->NumberOfTableEntries); pager_open(); if (pager_output(line)) { pager_close(); return (CMD_OK); } for (i = 0; i < ST->NumberOfTableEntries; i++) { EFI_GUID *guid; printf(" "); guid = &ST->ConfigurationTable[i].VendorGuid; if (!memcmp(guid, &mps, sizeof(EFI_GUID))) printf("MPS Table"); else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) printf("ACPI Table"); else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) printf("ACPI 2.0 Table"); else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) printf("SMBIOS Table %p", ST->ConfigurationTable[i].VendorTable); else if (!memcmp(guid, &smbios3, sizeof(EFI_GUID))) printf("SMBIOS3 Table"); else if (!memcmp(guid, &dxe, sizeof(EFI_GUID))) printf("DXE Table"); else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID))) printf("HOB List Table"); else if (!memcmp(guid, &lzmadecomp, sizeof(EFI_GUID))) printf("LZMA Compression"); else if (!memcmp(guid, &mpcore, sizeof(EFI_GUID))) printf("ARM MpCore Information Table"); else if (!memcmp(guid, &esrt, sizeof(EFI_GUID))) printf("ESRT Table"); else if (!memcmp(guid, &memtype, sizeof(EFI_GUID))) printf("Memory Type Information Table"); else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID))) printf("Debug Image Info Table"); else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID))) printf("FDT Table"); else printf("Unknown Table (%s)", guid_to_string(guid)); snprintf(line, sizeof(line), " at %p\n", ST->ConfigurationTable[i].VendorTable); if (pager_output(line)) break; } pager_close(); return (CMD_OK); } COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); static int command_mode(int argc, char *argv[]) { UINTN cols, rows; unsigned int mode; int i; char *cp; char rowenv[8]; EFI_STATUS status; SIMPLE_TEXT_OUTPUT_INTERFACE *conout; extern void HO(void); conout = ST->ConOut; if (argc > 1) { mode = strtol(argv[1], &cp, 0); if (cp[0] != '\0') { printf("Invalid mode\n"); return (CMD_ERROR); } status = conout->QueryMode(conout, mode, &cols, &rows); if (EFI_ERROR(status)) { printf("invalid mode %d\n", mode); return (CMD_ERROR); } status = conout->SetMode(conout, mode); if (EFI_ERROR(status)) { printf("couldn't set mode %d\n", mode); return (CMD_ERROR); } sprintf(rowenv, "%u", (unsigned)rows); setenv("LINES", rowenv, 1); HO(); /* set cursor */ return (CMD_OK); } printf("Current mode: %d\n", conout->Mode->Mode); for (i = 0; i <= conout->Mode->MaxMode; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) continue; printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, (unsigned)rows); } if (i != 0) printf("Select a mode with the command \"mode \"\n"); return (CMD_OK); } #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); /* * Since proper fdt command handling function is defined in fdt_loader_cmd.c, * and declaring it as extern is in contradiction with COMMAND_SET() macro * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif /* * Chain load another efi loader. */ static int command_chain(int argc, char *argv[]) { EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; struct stat st; struct devdesc *dev; char *name, *path; void *buf; int fd; if (argc < 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } name = argv[1]; if ((fd = open(name, O_RDONLY)) < 0) { command_errmsg = "no such file"; return (CMD_ERROR); } if (fstat(fd, &st) < -1) { command_errmsg = "stat failed"; close(fd); return (CMD_ERROR); } status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); if (status != EFI_SUCCESS) { command_errmsg = "failed to allocate buffer"; close(fd); return (CMD_ERROR); } if (read(fd, buf, st.st_size) != st.st_size) { command_errmsg = "error while reading the file"; (void)BS->FreePool(buf); close(fd); return (CMD_ERROR); } close(fd); status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); (void)BS->FreePool(buf); if (status != EFI_SUCCESS) { command_errmsg = "LoadImage failed"; return (CMD_ERROR); } status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, (void **)&loaded_image); if (argc > 2) { int i, len = 0; CHAR16 *argp; for (i = 2; i < argc; i++) len += strlen(argv[i]) + 1; len *= sizeof (*argp); loaded_image->LoadOptions = argp = malloc (len); loaded_image->LoadOptionsSize = len; for (i = 2; i < argc; i++) { char *ptr = argv[i]; while (*ptr) *(argp++) = *(ptr++); *(argp++) = ' '; } *(--argv) = 0; } if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) { #ifdef EFI_ZFS_BOOT struct zfs_devdesc *z_dev; #endif struct disk_devdesc *d_dev; pdinfo_t *hd, *pd; switch (dev->d_dev->dv_type) { #ifdef EFI_ZFS_BOOT case DEVT_ZFS: z_dev = (struct zfs_devdesc *)dev; loaded_image->DeviceHandle = efizfs_get_handle_by_guid(z_dev->pool_guid); break; #endif case DEVT_NET: loaded_image->DeviceHandle = efi_find_handle(dev->d_dev, dev->d_unit); break; default: hd = efiblk_get_pdinfo(dev); if (STAILQ_EMPTY(&hd->pd_part)) { loaded_image->DeviceHandle = hd->pd_handle; break; } d_dev = (struct disk_devdesc *)dev; STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { /* * d_partition should be 255 */ if (pd->pd_unit == (uint32_t)d_dev->d_slice) { loaded_image->DeviceHandle = pd->pd_handle; break; } } break; } } dev_cleanup(); status = BS->StartImage(loaderhandle, NULL, NULL); if (status != EFI_SUCCESS) { command_errmsg = "StartImage failed"; free(loaded_image->LoadOptions); loaded_image->LoadOptions = NULL; status = BS->UnloadImage(loaded_image); return (CMD_ERROR); } return (CMD_ERROR); /* not reached */ } COMMAND_SET(chain, "chain", "chain load file", command_chain); Index: stable/11/stand/i386/loader/main.c =================================================================== --- stable/11/stand/i386/loader/main.c (revision 344289) +++ stable/11/stand/i386/loader/main.c (revision 344290) @@ -1,409 +1,406 @@ /*- * Copyright (c) 1998 Michael Smith * 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$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "common/bootargs.h" #include "libi386/libi386.h" #include "libi386/smbios.h" #include "btxv86.h" #ifdef LOADER_ZFS_SUPPORT #include "../zfs/libzfs.h" #endif CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; static uint32_t initial_howto; static uint32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_GELI_SUPPORT #include "geliboot.h" struct geli_boot_args *gargs; #endif #ifdef LOADER_ZFS_SUPPORT struct zfs_boot_args *zargs; static void i386_zfs_probe(void); #endif -/* from vers.c */ -extern char bootprog_info[]; - /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; int main(void) { int i; /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = i386_zfs_probe; #ifdef LOADER_GELI_SUPPORT if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) { if (zargs->size >= offsetof(struct zfs_boot_args, keybuf_sentinel) && zargs->keybuf_sentinel == KEYBUF_SENTINEL) { geli_save_keybuf(zargs->keybuf); } if (zargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", zargs->gelipw, 1); explicit_bzero(zargs->gelipw, sizeof(zargs->gelipw)); } } } #endif /* LOADER_GELI_SUPPORT */ #else /* !LOADER_ZFS_SUPPORT */ #ifdef LOADER_GELI_SUPPORT if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { gargs = (struct geli_boot_args *)(kargs + 1); if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) { if (gargs->keybuf_sentinel == KEYBUF_SENTINEL) { geli_save_keybuf(gargs->keybuf); } if (gargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", gargs->gelipw, 1); explicit_bzero(gargs->gelipw, sizeof(gargs->gelipw)); } } } #endif /* LOADER_GELI_SUPPORT */ #endif /* LOADER_ZFS_SUPPORT */ /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } /* detect ACPI for future reference */ biosacpi_detect(); /* detect SMBIOS for future reference */ smbios_detect(NULL); /* detect PCI BIOS for future reference */ biospci_detect(); printf("\n%s", bootprog_info); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ bios_getsmap(); interact(); /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; #ifdef LOADER_ZFS_SUPPORT char buf[20]; #endif int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.dd.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.dd.d_dev = &bioscd; new_currdev.dd.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.dd.d_dev = &pxedisk; new_currdev.dd.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } #ifdef LOADER_ZFS_SUPPORT } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { zargs = NULL; /* check for new style extended argument */ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { /* sufficient data is provided */ new_currdev.d_kind.zfs.pool_guid = zargs->pool; new_currdev.d_kind.zfs.root_guid = zargs->root; if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { sprintf(buf, "%llu", zargs->primary_pool); setenv("vfs.zfs.boot.primary_pool", buf, 1); sprintf(buf, "%llu", zargs->primary_vdev); setenv("vfs.zfs.boot.primary_vdev", buf, 1); } } else { /* old style zfsboot block */ new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; new_currdev.d_kind.zfs.root_guid = 0; } new_currdev.dd.d_dev = &zfs_dev; #endif } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.dd.d_dev->dv_type == biosdisk.dv_type) && ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.dd.d_unit = 0; } #ifdef LOADER_ZFS_SUPPORT if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) init_zfs_bootenv(zfs_fmtdev(&new_currdev)); #endif env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } /* ISA bus access functions for PnP. */ static int isa_inb(int port) { return (inb(port)); } static void isa_outb(int port, int value) { outb(port, value); } #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void) { char devname[32]; int unit; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. */ for (unit = 0; unit < MAXBDDEV; unit++) { if (bd_unit2bios(unit) == -1) break; sprintf(devname, "disk%d:", unit); zfs_probe_dev(devname, NULL); } } #endif Index: stable/11/stand/mips/beri/loader/loader.h =================================================================== --- stable/11/stand/mips/beri/loader/loader.h (revision 344289) +++ stable/11/stand/mips/beri/loader/loader.h (revision 344290) @@ -1,64 +1,61 @@ /*- * Copyright (c) 2013-2014 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * 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. * * $FreeBSD$ */ #ifndef _BOOT_LOADER_H_ #define _BOOT_LOADER_H_ /* beri_console.c */ extern struct console altera_jtag_uart_console; /* beri_disk.c */ extern struct devsw beri_cfi_disk; extern struct devsw beri_sdcard_disk; /* devicename.c */ struct env_var; int beri_arch_setcurrdev(struct env_var *, int, const void *); char *beri_arch_fmtdev(void *); int beri_arch_getdev(void **, const char *, const char **); /* exec.c */ extern struct file_format beri_elf; /* main.c */ extern int boot2_argc; extern char **boot2_argv; extern char **boot2_envv; extern struct bootinfo boot2_bootinfo; /* metadata.c */ int md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtbp); -/* vers.c */ -extern char bootprog_info[]; - #endif /* !_BOOT_LOADER_H_ */ Index: stable/11/stand/pc98/loader/main.c =================================================================== --- stable/11/stand/pc98/loader/main.c (revision 344289) +++ stable/11/stand/pc98/loader/main.c (revision 344290) @@ -1,321 +1,318 @@ /*- * Copyright (c) 1998 Michael Smith * 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$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include #include #include #include "bootstrap.h" #include "common/bootargs.h" #include "libi386/libi386.h" #include "libpc98/libpc98.h" #include "btxv86.h" CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; static u_int32_t initial_howto; static u_int32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); -/* from vers.c */ -extern char bootprog_info[]; - /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; static uint64_t pc98_loadaddr(u_int type, void *data, uint64_t addr) { struct stat st; if (type == LOAD_ELF) return (roundup(addr, PAGE_SIZE)); /* We cannot use 15M-16M area on pc98. */ if (type == LOAD_RAW && addr < 0x1000000 && stat(data, &st) == 0 && (st.st_size == -1 || addr + st.st_size > 0xf00000)) addr = 0x1000000; return (addr); } int main(void) { int i; /* Set machine type to PC98_SYSTEM_PARAMETER. */ set_machine_type(); /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; archsw.arch_loadaddr = pc98_loadaddr; /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } printf("\n%s", bootprog_info); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ interact(); /* doesn't return */ /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; int major; int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.dd.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.dd.d_dev = &bioscd; new_currdev.dd.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.dd.d_dev = &pxedisk; new_currdev.dd.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; major = B_TYPE(initial_bootdev); /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { /* biosdev doesn't match major */ if (B_TYPE(initial_bootdev) == 6) biosdev = 0x30 + B_UNIT(initial_bootdev); else biosdev = (major << 3) + 0x80 + B_UNIT(initial_bootdev); } } /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.dd.d_dev->dv_type == biosdisk.dv_type) && ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.dd.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } /* ISA bus access functions for PnP. */ static int isa_inb(int port) { return (inb(port)); } static void isa_outb(int port, int value) { outb(port, value); } Index: stable/11/stand/powerpc/kboot/main.c =================================================================== --- stable/11/stand/powerpc/kboot/main.c (revision 344289) +++ stable/11/stand/powerpc/kboot/main.c (revision 344290) @@ -1,507 +1,505 @@ /*- * Copyright (C) 2010-2014 Nathan Whitehorn * 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 ``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 TOOLS GMBH 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 #define _KERNEL #include #include "bootstrap.h" #include "host_syscall.h" struct arch_switch archsw; extern void *_end; -extern char bootprog_info[]; - int kboot_getdev(void **vdev, const char *devspec, const char **path); ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len); ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len); int kboot_autoload(void); uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr); int kboot_setcurrdev(struct env_var *ev, int flags, const void *value); static void kboot_kseg_get(int *nseg, void **ptr); extern int command_fdt_internal(int argc, char *argv[]); struct region_desc { uint64_t start; uint64_t end; }; static uint64_t kboot_get_phys_load_segment(void) { int fd; uint64_t entry[2]; static uint64_t load_segment = ~(0UL); uint64_t val_64; uint32_t val_32; struct region_desc rsvd_reg[32]; int rsvd_reg_cnt = 0; int ret, a, b; uint64_t start, end; if (load_segment == ~(0UL)) { /* Default load address is 0x00000000 */ load_segment = 0UL; /* Read reserved regions */ fd = host_open("/proc/device-tree/reserved-ranges", O_RDONLY, 0); if (fd >= 0) { while (host_read(fd, &entry[0], sizeof(entry)) == sizeof(entry)) { rsvd_reg[rsvd_reg_cnt].start = be64toh(entry[0]); rsvd_reg[rsvd_reg_cnt].end = be64toh(entry[1]) + rsvd_reg[rsvd_reg_cnt].start - 1; rsvd_reg_cnt++; } host_close(fd); } /* Read where the kernel ends */ fd = host_open("/proc/device-tree/chosen/linux,kernel-end", O_RDONLY, 0); if (fd >= 0) { ret = host_read(fd, &val_64, sizeof(val_64)); if (ret == sizeof(uint64_t)) { rsvd_reg[rsvd_reg_cnt].start = 0; rsvd_reg[rsvd_reg_cnt].end = be64toh(val_64) - 1; } else { memcpy(&val_32, &val_64, sizeof(val_32)); rsvd_reg[rsvd_reg_cnt].start = 0; rsvd_reg[rsvd_reg_cnt].end = be32toh(val_32) - 1; } rsvd_reg_cnt++; host_close(fd); } /* Read memory size (SOCKET0 only) */ fd = host_open("/proc/device-tree/memory@0/reg", O_RDONLY, 0); if (fd < 0) fd = host_open("/proc/device-tree/memory/reg", O_RDONLY, 0); if (fd >= 0) { ret = host_read(fd, &entry, sizeof(entry)); /* Memory range in start:length format */ entry[0] = be64toh(entry[0]); entry[1] = be64toh(entry[1]); /* Reserve everything what is before start */ if (entry[0] != 0) { rsvd_reg[rsvd_reg_cnt].start = 0; rsvd_reg[rsvd_reg_cnt].end = entry[0] - 1; rsvd_reg_cnt++; } /* Reserve everything what is after end */ if (entry[1] != 0xffffffffffffffffUL) { rsvd_reg[rsvd_reg_cnt].start = entry[0] + entry[1]; rsvd_reg[rsvd_reg_cnt].end = 0xffffffffffffffffUL; rsvd_reg_cnt++; } host_close(fd); } /* Sort entries in ascending order (bubble) */ for (a = rsvd_reg_cnt - 1; a > 0; a--) { for (b = 0; b < a; b++) { if (rsvd_reg[b].start > rsvd_reg[b + 1].start) { struct region_desc tmp; tmp = rsvd_reg[b]; rsvd_reg[b] = rsvd_reg[b + 1]; rsvd_reg[b + 1] = tmp; } } } /* Join overlapping/adjacent regions */ for (a = 0; a < rsvd_reg_cnt - 1; ) { if ((rsvd_reg[a + 1].start >= rsvd_reg[a].start) && ((rsvd_reg[a + 1].start - 1) <= rsvd_reg[a].end)) { /* We have overlapping/adjacent regions! */ rsvd_reg[a].end = MAX(rsvd_reg[a].end, rsvd_reg[a + a].end); for (b = a + 1; b < rsvd_reg_cnt - 1; b++) rsvd_reg[b] = rsvd_reg[b + 1]; rsvd_reg_cnt--; } else a++; } /* Find the first free region */ if (rsvd_reg_cnt > 0) { start = 0; end = rsvd_reg[0].start; for (a = 0; a < rsvd_reg_cnt - 1; a++) { if ((start >= rsvd_reg[a].start) && (start <= rsvd_reg[a].end)) { start = rsvd_reg[a].end + 1; end = rsvd_reg[a + 1].start; } else break; } if (start != end) { uint64_t align = 64UL*1024UL*1024UL; /* Align both to 64MB boundary */ start = (start + align - 1UL) & ~(align - 1UL); end = ((end + 1UL) & ~(align - 1UL)) - 1UL; if (start < end) load_segment = start; } } } return (load_segment); } uint8_t kboot_get_kernel_machine_bits(void) { static uint8_t bits = 0; struct old_utsname utsname; int ret; if (bits == 0) { /* Default is 32-bit kernel */ bits = 32; /* Try to get system type */ memset(&utsname, 0, sizeof(utsname)); ret = host_uname(&utsname); if (ret == 0) { if (strcmp(utsname.machine, "ppc64") == 0) bits = 64; else if (strcmp(utsname.machine, "ppc64le") == 0) bits = 64; } } return (bits); } int kboot_getdev(void **vdev, const char *devspec, const char **path) { int i; const char *devpath, *filepath; struct devsw *dv; struct devdesc *desc; if (strchr(devspec, ':') != NULL) { devpath = devspec; filepath = strchr(devspec, ':') + 1; } else { devpath = getenv("currdev"); filepath = devspec; } for (i = 0; (dv = devsw[i]) != NULL; i++) { if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0) goto found; } return (ENOENT); found: if (path != NULL && filepath != NULL) *path = filepath; else if (path != NULL) *path = strchr(devspec, ':') + 1; if (vdev != NULL) { desc = malloc(sizeof(*desc)); desc->d_dev = dv; desc->d_unit = 0; desc->d_opendata = strdup(devpath); *vdev = desc; } return (0); } int main(int argc, const char **argv) { void *heapbase; const size_t heapsize = 15*1024*1024; const char *bootdev; /* * Set the heap to one page after the end of the loader. */ heapbase = host_getmem(heapsize); setheap(heapbase, heapbase + heapsize); /* * Set up console. */ cons_probe(); /* Choose bootdev if provided */ if (argc > 1) bootdev = argv[1]; else bootdev = ""; printf("Boot device: %s\n", bootdev); archsw.arch_getdev = kboot_getdev; archsw.arch_copyin = kboot_copyin; archsw.arch_copyout = kboot_copyout; archsw.arch_readin = kboot_readin; archsw.arch_autoload = kboot_autoload; archsw.arch_loadaddr = kboot_loadaddr; archsw.arch_kexec_kseg_get = kboot_kseg_get; printf("\n%s", bootprog_info); setenv("currdev", bootdev, 1); setenv("loaddev", bootdev, 1); setenv("LINES", "24", 1); setenv("usefdt", "1", 1); interact(); /* doesn't return */ return (0); } void exit(int code) { while (1); /* XXX: host_exit */ __unreachable(); } void delay(int usecs) { struct host_timeval tvi, tv; uint64_t ti, t; host_gettimeofday(&tvi, NULL); ti = tvi.tv_sec*1000000 + tvi.tv_usec; do { host_gettimeofday(&tv, NULL); t = tv.tv_sec*1000000 + tv.tv_usec; } while (t < ti + usecs); } time_t getsecs(void) { struct host_timeval tv; host_gettimeofday(&tv, NULL); return (tv.tv_sec); } time_t time(time_t *tloc) { time_t rv; rv = getsecs(); if (tloc != NULL) *tloc = rv; return (rv); } struct kexec_segment { void *buf; int bufsz; void *mem; int memsz; }; struct kexec_segment loaded_segments[128]; int nkexec_segments = 0; static ssize_t get_phys_buffer(vm_offset_t dest, const size_t len, void **buf) { int i = 0; const size_t segsize = 4*1024*1024; for (i = 0; i < nkexec_segments; i++) { if (dest >= (vm_offset_t)loaded_segments[i].mem && dest < (vm_offset_t)loaded_segments[i].mem + loaded_segments[i].memsz) goto out; } loaded_segments[nkexec_segments].buf = host_getmem(segsize); loaded_segments[nkexec_segments].bufsz = segsize; loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize); loaded_segments[nkexec_segments].memsz = segsize; i = nkexec_segments; nkexec_segments++; out: *buf = loaded_segments[i].buf + (dest - (vm_offset_t)loaded_segments[i].mem); return (min(len,loaded_segments[i].bufsz - (dest - (vm_offset_t)loaded_segments[i].mem))); } ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len) { ssize_t segsize, remainder; void *destbuf; remainder = len; do { segsize = get_phys_buffer(dest, remainder, &destbuf); bcopy(src, destbuf, segsize); remainder -= segsize; src += segsize; dest += segsize; } while (remainder > 0); return (len); } ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len) { ssize_t segsize, remainder; void *srcbuf; remainder = len; do { segsize = get_phys_buffer(src, remainder, &srcbuf); bcopy(srcbuf, dest, segsize); remainder -= segsize; src += segsize; dest += segsize; } while (remainder > 0); return (len); } ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len) { void *buf; size_t resid, chunk, get; ssize_t got; vm_offset_t p; p = dest; chunk = min(PAGE_SIZE, len); buf = malloc(chunk); if (buf == NULL) { printf("kboot_readin: buf malloc failed\n"); return (0); } for (resid = len; resid > 0; resid -= got, p += got) { get = min(chunk, resid); got = read(fd, buf, get); if (got <= 0) { if (got < 0) printf("kboot_readin: read failed\n"); break; } kboot_copyin(buf, p, got); } free (buf); return (len - resid); } int kboot_autoload(void) { return (0); } uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr) { if (type == LOAD_ELF) addr = roundup(addr, PAGE_SIZE); else addr += kboot_get_phys_load_segment(); return (addr); } static void kboot_kseg_get(int *nseg, void **ptr) { #if 0 int a; for (a = 0; a < nkexec_segments; a++) { printf("kseg_get: %jx %jx %jx %jx\n", (uintmax_t)loaded_segments[a].buf, (uintmax_t)loaded_segments[a].bufsz, (uintmax_t)loaded_segments[a].mem, (uintmax_t)loaded_segments[a].memsz); } #endif *nseg = nkexec_segments; *ptr = &loaded_segments[0]; } void _start(int argc, const char **argv, char **env) { register volatile void **sp asm("r1"); main((int)sp[0], (const char **)&sp[1]); } /* * Since proper fdt command handling function is defined in fdt_loader_cmd.c, * and declaring it as extern is in contradiction with COMMAND_SET() macro * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); Index: stable/11/stand/powerpc/ofw/main.c =================================================================== --- stable/11/stand/powerpc/ofw/main.c (revision 344289) +++ stable/11/stand/powerpc/ofw/main.c (revision 344290) @@ -1,200 +1,199 @@ /*- * Copyright (c) 2000 Benno Rice * Copyright (c) 2000 Stephane Potvin * 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 AUTHORS 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 "openfirm.h" #include "libofw.h" #include "bootstrap.h" #include struct arch_switch archsw; /* MI/MD interface boundary */ extern char end[]; -extern char bootprog_info[]; uint32_t acells, scells; static char bootargs[128]; #define HEAP_SIZE 0x800000 static char heap[HEAP_SIZE]; // In BSS, so uses no space #define OF_puts(fd, text) OF_write(fd, text, strlen(text)) static __inline register_t mfmsr(void) { register_t value; __asm __volatile ("mfmsr %0" : "=r"(value)); return (value); } void init_heap(void) { bzero(heap, HEAP_SIZE); setheap(heap, (void *)((int)heap + HEAP_SIZE)); } uint64_t memsize(void) { phandle_t memoryp; cell_t reg[24]; int i, sz; uint64_t memsz; memsz = 0; memoryp = OF_instance_to_package(memory); sz = OF_getprop(memoryp, "reg", ®, sizeof(reg)); sz /= sizeof(reg[0]); for (i = 0; i < sz; i += (acells + scells)) { if (scells > 1) memsz += (uint64_t)reg[i + acells] << 32; memsz += reg[i + acells + scells - 1]; } return (memsz); } int main(int (*openfirm)(void *)) { phandle_t root; int i; char bootpath[64]; char *ch; int bargc; char **bargv; /* * Initialise the Open Firmware routines by giving them the entry point. */ OF_init(openfirm); root = OF_finddevice("/"); scells = acells = 1; OF_getprop(root, "#address-cells", &acells, sizeof(acells)); OF_getprop(root, "#size-cells", &scells, sizeof(scells)); /* * Initialise the heap as early as possible. Once this is done, * alloc() is usable. The stack is buried inside us, so this is * safe. */ init_heap(); /* * Set up console. */ cons_probe(); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("\n%s", bootprog_info); printf("Memory: %lldKB\n", memsize() / 1024); OF_getprop(chosen, "bootpath", bootpath, 64); ch = strchr(bootpath, ':'); *ch = '\0'; printf("Booted from: %s\n", bootpath); printf("\n"); /* * Only parse the first bootarg if present. It should * be simple to handle extra arguments */ OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs)); bargc = 0; parse(&bargc, &bargv, bootargs); if (bargc == 1) env_setenv("currdev", EV_VOLATILE, bargv[0], ofw_setcurrdev, env_nounset); else env_setenv("currdev", EV_VOLATILE, bootpath, ofw_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, bootpath, env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ /* * On non-Apple hardware, where it works reliably, pass flattened * device trees to the kernel by default instead of OF CI pointers. * Apple hardware is the only virtual-mode OF implementation in * existence, so far as I am aware, so use that as a flag. */ if (!(mfmsr() & PSL_DR)) setenv("usefdt", "1", 1); archsw.arch_getdev = ofw_getdev; archsw.arch_copyin = ofw_copyin; archsw.arch_copyout = ofw_copyout; archsw.arch_readin = ofw_readin; archsw.arch_autoload = ofw_autoload; interact(); /* doesn't return */ OF_exit(); return 0; } COMMAND_SET(halt, "halt", "halt the system", command_halt); static int command_halt(int argc, char *argv[]) { OF_exit(); return (CMD_OK); } COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); int command_memmap(int argc, char **argv) { ofw_memmap(acells); return (CMD_OK); } Index: stable/11/stand/sparc64/loader/main.c =================================================================== --- stable/11/stand/sparc64/loader/main.c (revision 344289) +++ stable/11/stand/sparc64/loader/main.c (revision 344290) @@ -1,988 +1,986 @@ /*- * Initial implementation: * Copyright (c) 2001 Robert Drehmel * All rights reserved. * * As long as the above copyright statement and this notice remain * unchanged, you can do what ever you want with this file. */ /*- * Copyright (c) 2008 - 2012 Marius Strobl * 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$"); /* * FreeBSD/sparc64 kernel loader - machine dependent part * * - implements copyin and readin functions that map kernel * pages on demand. The machine independent code does not * know the size of the kernel early enough to pre-enter * TTEs and install just one 4MB mapping seemed to limiting * to me. */ #include #include #include #include #include #include #ifdef LOADER_ZFS_SUPPORT #include #include "../zfs/libzfs.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "libofw.h" #include "dev_net.h" -extern char bootprog_info[]; - enum { HEAPVA = 0x800000, HEAPSZ = 0x3000000, LOADSZ = 0x1000000 /* for kernel and modules */ }; /* At least Sun Fire V1280 require page sized allocations to be claimed. */ CTASSERT(HEAPSZ % PAGE_SIZE == 0); static struct mmu_ops { void (*tlb_init)(void); int (*mmu_mapin)(vm_offset_t va, vm_size_t len); } *mmu_ops; typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, void *openfirmware); static inline u_long dtlb_get_data_sun4u(u_int, u_int); static int dtlb_enter_sun4u(u_int, u_long data, vm_offset_t); static vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t); static inline u_long itlb_get_data_sun4u(u_int, u_int); static int itlb_enter_sun4u(u_int, u_long data, vm_offset_t); static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t); static void itlb_relocate_locked0_sun4u(void); static int sparc64_autoload(void); static ssize_t sparc64_readin(const int, vm_offset_t, const size_t); static ssize_t sparc64_copyin(const void *, vm_offset_t, size_t); static vm_offset_t claim_virt(vm_offset_t, size_t, int); static vm_offset_t alloc_phys(size_t, int); static int map_phys(int, size_t, vm_offset_t, vm_offset_t); static void release_phys(vm_offset_t, u_int); static int __elfN(exec)(struct preloaded_file *); static int mmu_mapin_sun4u(vm_offset_t, vm_size_t); static vm_offset_t init_heap(void); static phandle_t find_bsp_sun4u(phandle_t, uint32_t); const char *cpu_cpuid_prop_sun4u(void); uint32_t cpu_get_mid_sun4u(void); static void tlb_init_sun4u(void); #ifdef LOADER_DEBUG typedef uint64_t tte_t; static void pmap_print_tlb_sun4u(void); static void pmap_print_tte_sun4u(tte_t, tte_t); #endif static struct mmu_ops mmu_ops_sun4u = { tlb_init_sun4u, mmu_mapin_sun4u }; /* sun4u */ struct tlb_entry *dtlb_store; struct tlb_entry *itlb_store; u_int dtlb_slot; u_int itlb_slot; static int cpu_impl; static u_int dtlb_slot_max; static u_int itlb_slot_max; static u_int tlb_locked; static vm_offset_t curkva = 0; static vm_offset_t heapva; static char bootpath[64]; static phandle_t root; #ifdef LOADER_ZFS_SUPPORT static struct zfs_devdesc zfs_currdev; #endif /* * Machine dependent structures that the machine independent * loader part uses. */ struct devsw *devsw[] = { #ifdef LOADER_DISK_SUPPORT &ofwdisk, #endif #ifdef LOADER_NET_SUPPORT &netdev, #endif #ifdef LOADER_ZFS_SUPPORT &zfs_dev, #endif NULL }; struct arch_switch archsw; static struct file_format sparc64_elf = { __elfN(loadfile), __elfN(exec) }; struct file_format *file_formats[] = { &sparc64_elf, NULL }; struct fs_ops *file_system[] = { #ifdef LOADER_ZFS_SUPPORT &zfs_fsops, #endif #ifdef LOADER_UFS_SUPPORT &ufs_fsops, #endif #ifdef LOADER_CD9660_SUPPORT &cd9660_fsops, #endif #ifdef LOADER_ZIP_SUPPORT &zipfs_fsops, #endif #ifdef LOADER_GZIP_SUPPORT &gzipfs_fsops, #endif #ifdef LOADER_BZIP2_SUPPORT &bzipfs_fsops, #endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif #ifdef LOADER_TFTP_SUPPORT &tftp_fsops, #endif NULL }; struct netif_driver *netif_drivers[] = { #ifdef LOADER_NET_SUPPORT &ofwnet, #endif NULL }; extern struct console ofwconsole; struct console *consoles[] = { &ofwconsole, NULL }; #ifdef LOADER_DEBUG static int watch_phys_set_mask(vm_offset_t pa, u_long mask) { u_long lsucr; stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); lsucr = ldxa(0, ASI_LSU_CTL_REG); lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | (mask << LSU_PM_SHIFT); stxa(0, ASI_LSU_CTL_REG, lsucr); return (0); } static int watch_phys_set(vm_offset_t pa, int sz) { u_long off; off = (u_long)pa & 7; /* Test for misaligned watch points. */ if (off + sz > 8) return (-1); return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); } static int watch_virt_set_mask(vm_offset_t va, u_long mask) { u_long lsucr; stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); lsucr = ldxa(0, ASI_LSU_CTL_REG); lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | (mask << LSU_VM_SHIFT); stxa(0, ASI_LSU_CTL_REG, lsucr); return (0); } static int watch_virt_set(vm_offset_t va, int sz) { u_long off; off = (u_long)va & 7; /* Test for misaligned watch points. */ if (off + sz > 8) return (-1); return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); } #endif /* * archsw functions */ static int sparc64_autoload(void) { return (0); } static ssize_t sparc64_readin(const int fd, vm_offset_t va, const size_t len) { mmu_ops->mmu_mapin(va, len); return (read(fd, (void *)va, len)); } static ssize_t sparc64_copyin(const void *src, vm_offset_t dest, size_t len) { mmu_ops->mmu_mapin(dest, len); memcpy((void *)dest, src, len); return (len); } /* * other MD functions */ static vm_offset_t claim_virt(vm_offset_t virt, size_t size, int align) { vm_offset_t mva; if (OF_call_method("claim", mmu, 3, 1, virt, size, align, &mva) == -1) return ((vm_offset_t)-1); return (mva); } static vm_offset_t alloc_phys(size_t size, int align) { cell_t phys_hi, phys_low; if (OF_call_method("claim", memory, 2, 2, size, align, &phys_low, &phys_hi) == -1) return ((vm_offset_t)-1); return ((vm_offset_t)phys_hi << 32 | phys_low); } static int map_phys(int mode, size_t size, vm_offset_t virt, vm_offset_t phys) { return (OF_call_method("map", mmu, 5, 0, (uint32_t)phys, (uint32_t)(phys >> 32), virt, size, mode)); } static void release_phys(vm_offset_t phys, u_int size) { (void)OF_call_method("release", memory, 3, 0, (uint32_t)phys, (uint32_t)(phys >> 32), size); } static int __elfN(exec)(struct preloaded_file *fp) { struct file_metadata *fmp; vm_offset_t mdp; Elf_Addr entry; Elf_Ehdr *e; int error; if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) return (EFTYPE); e = (Elf_Ehdr *)&fmp->md_data; if ((error = md_load64(fp->f_args, &mdp, NULL)) != 0) return (error); printf("jumping to kernel entry at %#lx.\n", e->e_entry); #ifdef LOADER_DEBUG pmap_print_tlb_sun4u(); #endif dev_cleanup(); entry = e->e_entry; OF_release((void *)heapva, HEAPSZ); ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); panic("%s: exec returned", __func__); } static inline u_long dtlb_get_data_sun4u(u_int tlb, u_int slot) { u_long data, pstate; slot = TLB_DAR_SLOT(tlb, slot); /* * We read ASI_DTLB_DATA_ACCESS_REG twice back-to-back in order to * work around errata of USIII and beyond. */ pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); (void)ldxa(slot, ASI_DTLB_DATA_ACCESS_REG); data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG); wrpr(pstate, pstate, 0); return (data); } static inline u_long itlb_get_data_sun4u(u_int tlb, u_int slot) { u_long data, pstate; slot = TLB_DAR_SLOT(tlb, slot); /* * We read ASI_DTLB_DATA_ACCESS_REG twice back-to-back in order to * work around errata of USIII and beyond. */ pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); (void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG); data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG); wrpr(pstate, pstate, 0); return (data); } static vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t va) { u_long pstate, reg; u_int i, tlb; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); for (i = 0; i < dtlb_slot_max; i++) { reg = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_DTLB_TAG_READ_REG); if (TLB_TAR_VA(reg) != va) continue; reg = dtlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); reg >>= TD_PA_SHIFT; if (cpu_impl == CPU_IMPL_SPARC64V || cpu_impl >= CPU_IMPL_ULTRASPARCIII) return (reg & TD_PA_CH_MASK); return (reg & TD_PA_SF_MASK); } wrpr(pstate, pstate, 0); return (-1); } static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t va) { u_long pstate, reg; int i; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); for (i = 0; i < itlb_slot_max; i++) { reg = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_TAG_READ_REG); if (TLB_TAR_VA(reg) != va) continue; reg = itlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); reg >>= TD_PA_SHIFT; if (cpu_impl == CPU_IMPL_SPARC64V || cpu_impl >= CPU_IMPL_ULTRASPARCIII) return (reg & TD_PA_CH_MASK); return (reg & TD_PA_SF_MASK); } wrpr(pstate, pstate, 0); return (-1); } static int dtlb_enter_sun4u(u_int index, u_long data, vm_offset_t virt) { return (OF_call_method("SUNW,dtlb-load", mmu, 3, 0, index, data, virt)); } static int itlb_enter_sun4u(u_int index, u_long data, vm_offset_t virt) { if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp && index == 0 && (data & TD_L) != 0) panic("%s: won't enter locked TLB entry at index 0 on USIII+", __func__); return (OF_call_method("SUNW,itlb-load", mmu, 3, 0, index, data, virt)); } static void itlb_relocate_locked0_sun4u(void) { u_long data, pstate, tag; int i; if (cpu_impl != CPU_IMPL_ULTRASPARCIIIp) return; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); data = itlb_get_data_sun4u(tlb_locked, 0); if ((data & (TD_V | TD_L)) != (TD_V | TD_L)) { wrpr(pstate, pstate, 0); return; } /* Flush the mapping of slot 0. */ tag = ldxa(TLB_DAR_SLOT(tlb_locked, 0), ASI_ITLB_TAG_READ_REG); stxa(TLB_DEMAP_VA(TLB_TAR_VA(tag)) | TLB_DEMAP_PRIMARY | TLB_DEMAP_PAGE, ASI_IMMU_DEMAP, 0); flush(0); /* The USIII-family ignores the address. */ /* * Search a replacement slot != 0 and enter the data and tag * that formerly were in slot 0. */ for (i = 1; i < itlb_slot_max; i++) { if ((itlb_get_data_sun4u(tlb_locked, i) & TD_V) != 0) continue; stxa(AA_IMMU_TAR, ASI_IMMU, tag); stxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_DATA_ACCESS_REG, data); flush(0); /* The USIII-family ignores the address. */ break; } wrpr(pstate, pstate, 0); if (i == itlb_slot_max) panic("%s: could not find a replacement slot", __func__); } static int mmu_mapin_sun4u(vm_offset_t va, vm_size_t len) { vm_offset_t pa, mva; u_long data; u_int index; if (va + len > curkva) curkva = va + len; pa = (vm_offset_t)-1; len += va & PAGE_MASK_4M; va &= ~PAGE_MASK_4M; while (len) { if (dtlb_va_to_pa_sun4u(va) == (vm_offset_t)-1 || itlb_va_to_pa_sun4u(va) == (vm_offset_t)-1) { /* Allocate a physical page, claim the virtual area. */ if (pa == (vm_offset_t)-1) { pa = alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); if (pa == (vm_offset_t)-1) panic("%s: out of memory", __func__); mva = claim_virt(va, PAGE_SIZE_4M, 0); if (mva != va) panic("%s: can't claim virtual page " "(wanted %#lx, got %#lx)", __func__, va, mva); /* * The mappings may have changed, be paranoid. */ continue; } /* * Actually, we can only allocate two pages less at * most (depending on the kernel TSB size). */ if (dtlb_slot >= dtlb_slot_max) panic("%s: out of dtlb_slots", __func__); if (itlb_slot >= itlb_slot_max) panic("%s: out of itlb_slots", __func__); data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | TD_CV | TD_P | TD_W; dtlb_store[dtlb_slot].te_pa = pa; dtlb_store[dtlb_slot].te_va = va; index = dtlb_slot_max - dtlb_slot - 1; if (dtlb_enter_sun4u(index, data, va) < 0) panic("%s: can't enter dTLB slot %d data " "%#lx va %#lx", __func__, index, data, va); dtlb_slot++; itlb_store[itlb_slot].te_pa = pa; itlb_store[itlb_slot].te_va = va; index = itlb_slot_max - itlb_slot - 1; if (itlb_enter_sun4u(index, data, va) < 0) panic("%s: can't enter iTLB slot %d data " "%#lx va %#lxd", __func__, index, data, va); itlb_slot++; pa = (vm_offset_t)-1; } len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; va += PAGE_SIZE_4M; } if (pa != (vm_offset_t)-1) release_phys(pa, PAGE_SIZE_4M); return (0); } static vm_offset_t init_heap(void) { /* There is no need for continuous physical heap memory. */ heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); return (heapva); } static phandle_t find_bsp_sun4u(phandle_t node, uint32_t bspid) { char type[sizeof("cpu")]; phandle_t child; uint32_t cpuid; for (; node > 0; node = OF_peer(node)) { child = OF_child(node); if (child > 0) { child = find_bsp_sun4u(child, bspid); if (child > 0) return (child); } else { if (OF_getprop(node, "device_type", type, sizeof(type)) <= 0) continue; if (strcmp(type, "cpu") != 0) continue; if (OF_getprop(node, cpu_cpuid_prop_sun4u(), &cpuid, sizeof(cpuid)) <= 0) continue; if (cpuid == bspid) return (node); } } return (0); } const char * cpu_cpuid_prop_sun4u(void) { switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_SPARC64V: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: return ("upa-portid"); case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: return ("portid"); case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: return ("cpuid"); default: return (""); } } uint32_t cpu_get_mid_sun4u(void) { switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_SPARC64V: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: return (UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: return (FIREPLANE_CR_GET_AID(ldxa(AA_FIREPLANE_CONFIG, ASI_FIREPLANE_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: return (JBUS_CR_GET_JID(ldxa(0, ASI_JBUS_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: return (INTR_ID_GET_ID(ldxa(AA_INTR_ID, ASI_INTR_ID))); default: return (0); } } static void tlb_init_sun4u(void) { phandle_t bsp; cpu_impl = VER_IMPL(rdpr(ver)); switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: tlb_locked = TLB_DAR_T32; break; case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: tlb_locked = TLB_DAR_T16; break; case CPU_IMPL_SPARC64V: tlb_locked = TLB_DAR_FTLB; break; } bsp = find_bsp_sun4u(OF_child(root), cpu_get_mid_sun4u()); if (bsp == 0) panic("%s: no node for bootcpu?!?!", __func__); if (OF_getprop(bsp, "#dtlb-entries", &dtlb_slot_max, sizeof(dtlb_slot_max)) == -1 || OF_getprop(bsp, "#itlb-entries", &itlb_slot_max, sizeof(itlb_slot_max)) == -1) panic("%s: can't get TLB slot max.", __func__); if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp) { #ifdef LOADER_DEBUG printf("pre fixup:\n"); pmap_print_tlb_sun4u(); #endif /* * Relocate the locked entry in it16 slot 0 (if existent) * as part of working around Cheetah+ erratum 34. */ itlb_relocate_locked0_sun4u(); #ifdef LOADER_DEBUG printf("post fixup:\n"); pmap_print_tlb_sun4u(); #endif } dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); if (dtlb_store == NULL || itlb_store == NULL) panic("%s: can't allocate TLB store", __func__); } #ifdef LOADER_ZFS_SUPPORT static void sparc64_zfs_probe(void) { struct vtoc8 vtoc; char alias[64], devname[sizeof(alias) + sizeof(":x") - 1]; char type[sizeof("device_type")]; char *bdev, *dev, *odev; uint64_t guid, *guidp; int fd, len, part; phandle_t aliases, options; guid = 0; /* * Get the GUIDs of the ZFS pools on any additional disks listed in * the boot-device environment variable. */ if ((aliases = OF_finddevice("/aliases")) == -1) goto out; options = OF_finddevice("/options"); len = OF_getproplen(options, "boot-device"); if (len <= 0) goto out; bdev = odev = malloc(len + 1); if (bdev == NULL) goto out; if (OF_getprop(options, "boot-device", bdev, len) <= 0) goto out; bdev[len] = '\0'; while ((dev = strsep(&bdev, " ")) != NULL) { if (*dev == '\0') continue; strcpy(alias, dev); (void)OF_getprop(aliases, dev, alias, sizeof(alias)); if (OF_getprop(OF_finddevice(alias), "device_type", type, sizeof(type)) == -1) continue; if (strcmp(type, "block") != 0) continue; /* Find freebsd-zfs slices in the VTOC. */ fd = open(alias, O_RDONLY); if (fd == -1) continue; lseek(fd, 0, SEEK_SET); if (read(fd, &vtoc, sizeof(vtoc)) != sizeof(vtoc)) { close(fd); continue; } close(fd); for (part = 0; part < 8; part++) { if (part == 2 || vtoc.part[part].tag != VTOC_TAG_FREEBSD_ZFS) continue; (void)sprintf(devname, "%s:%c", alias, part + 'a'); /* Get the GUID of the ZFS pool on the boot device. */ if (strcmp(devname, bootpath) == 0) guidp = &guid; else guidp = NULL; if (zfs_probe_dev(devname, guidp) == ENXIO) break; } } free(odev); out: if (guid != 0) { zfs_currdev.pool_guid = guid; zfs_currdev.root_guid = 0; zfs_currdev.dd.d_dev = &zfs_dev; } } #endif /* LOADER_ZFS_SUPPORT */ int main(int (*openfirm)(void *)) { char compatible[32]; struct devsw **dp; /* * Tell the Open Firmware functions where they find the OFW gate. */ OF_init(openfirm); archsw.arch_getdev = ofw_getdev; archsw.arch_copyin = sparc64_copyin; archsw.arch_copyout = ofw_copyout; archsw.arch_readin = sparc64_readin; archsw.arch_autoload = sparc64_autoload; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = sparc64_zfs_probe; #endif if (init_heap() == (vm_offset_t)-1) OF_exit(); setheap((void *)heapva, (void *)(heapva + HEAPSZ)); /* * Probe for a console. */ cons_probe(); if ((root = OF_peer(0)) == -1) panic("%s: can't get root phandle", __func__); OF_getprop(root, "compatible", compatible, sizeof(compatible)); mmu_ops = &mmu_ops_sun4u; mmu_ops->tlb_init(); /* * Set up the current device. */ OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath)); /* * Initialize devices. */ for (dp = devsw; *dp != NULL; dp++) if ((*dp)->dv_init != 0) (*dp)->dv_init(); #ifdef LOADER_ZFS_SUPPORT if (zfs_currdev.pool_guid != 0) { (void)strncpy(bootpath, zfs_fmtdev(&zfs_currdev), sizeof(bootpath) - 1); bootpath[sizeof(bootpath) - 1] = '\0'; } else #endif /* * Sun compatible bootable CD-ROMs have a disk label placed before * the ISO 9660 data, with the actual file system being in the first * partition, while the other partitions contain pseudo disk labels * with embedded boot blocks for different architectures, which may * be followed by UFS file systems. * The firmware will set the boot path to the partition it boots from * ('f' in the sun4u/sun4v case), but we want the kernel to be loaded * from the ISO 9660 file system ('a'), so the boot path needs to be * altered. */ if (bootpath[strlen(bootpath) - 2] == ':' && bootpath[strlen(bootpath) - 1] == 'f') bootpath[strlen(bootpath) - 1] = 'a'; env_setenv("currdev", EV_VOLATILE, bootpath, ofw_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, bootpath, env_noset, env_nounset); printf("\n%s", bootprog_info); printf("bootpath=\"%s\"\n", bootpath); /* Give control to the machine independent loader code. */ interact(); return (1); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heapva, sbrk(0), heapva + HEAPSZ); return(CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); OF_exit(); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { OF_exit(); } #ifdef LOADER_DEBUG static const char *const page_sizes[] = { " 8k", " 64k", "512k", " 4m" }; static void pmap_print_tte_sun4u(tte_t tag, tte_t tte) { printf("%s %s ", page_sizes[(tte >> TD_SIZE_SHIFT) & TD_SIZE_MASK], tag & TD_G ? "G" : " "); printf(tte & TD_W ? "W " : " "); printf(tte & TD_P ? "\e[33mP\e[0m " : " "); printf(tte & TD_E ? "E " : " "); printf(tte & TD_CV ? "CV " : " "); printf(tte & TD_CP ? "CP " : " "); printf(tte & TD_L ? "\e[32mL\e[0m " : " "); printf(tte & TD_IE ? "IE " : " "); printf(tte & TD_NFO ? "NFO " : " "); printf("pa=0x%lx va=0x%lx ctx=%ld\n", TD_PA(tte), TLB_TAR_VA(tag), TLB_TAR_CTX(tag)); } static void pmap_print_tlb_sun4u(void) { tte_t tag, tte; u_long pstate; int i; pstate = rdpr(pstate); for (i = 0; i < itlb_slot_max; i++) { wrpr(pstate, pstate & ~PSTATE_IE, 0); tte = itlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); if (!(tte & TD_V)) continue; tag = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_TAG_READ_REG); printf("iTLB-%2u: ", i); pmap_print_tte_sun4u(tag, tte); } for (i = 0; i < dtlb_slot_max; i++) { wrpr(pstate, pstate & ~PSTATE_IE, 0); tte = dtlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); if (!(tte & TD_V)) continue; tag = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_DTLB_TAG_READ_REG); printf("dTLB-%2u: ", i); pmap_print_tte_sun4u(tag, tte); } } #endif Index: stable/11/stand/uboot/common/main.c =================================================================== --- stable/11/stand/uboot/common/main.c (revision 344289) +++ stable/11/stand/uboot/common/main.c (revision 344290) @@ -1,684 +1,683 @@ /*- * Copyright (c) 2000 Benno Rice * Copyright (c) 2000 Stephane Potvin * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski * 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 AUTHORS 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 "api_public.h" #include "bootstrap.h" #include "glue.h" #include "libuboot.h" #ifndef nitems #define nitems(x) (sizeof((x)) / sizeof((x)[0])) #endif #ifndef HEAP_SIZE #define HEAP_SIZE (2 * 1024 * 1024) #endif struct uboot_devdesc currdev; struct arch_switch archsw; /* MI/MD interface boundary */ int devs_no; uintptr_t uboot_heap_start; uintptr_t uboot_heap_end; struct device_type { const char *name; int type; } device_types[] = { { "disk", DEV_TYP_STOR }, { "ide", DEV_TYP_STOR | DT_STOR_IDE }, { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, { "sata", DEV_TYP_STOR | DT_STOR_SATA }, { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, { "usb", DEV_TYP_STOR | DT_STOR_USB }, { "net", DEV_TYP_NET } }; extern char end[]; -extern char bootprog_info[]; extern unsigned char _etext[]; extern unsigned char _edata[]; extern unsigned char __bss_start[]; extern unsigned char __sbss_start[]; extern unsigned char __sbss_end[]; extern unsigned char _end[]; #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); #endif static void dump_sig(struct api_signature *sig) { #ifdef DEBUG printf("signature:\n"); printf(" version\t= %d\n", sig->version); printf(" checksum\t= 0x%08x\n", sig->checksum); printf(" sc entry\t= 0x%08x\n", sig->syscall); #endif } static void dump_addr_info(void) { #ifdef DEBUG printf("\naddresses info:\n"); printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); printf(" _edata = 0x%08x\n", (uint32_t)_edata); printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); printf(" _end = 0x%08x\n", (uint32_t)_end); printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); #endif } static uint64_t memsize(struct sys_info *si, int flags) { uint64_t size; int i; size = 0; for (i = 0; i < si->mr_no; i++) if (si->mr[i].flags == flags && si->mr[i].size) size += (si->mr[i].size); return (size); } static void meminfo(void) { uint64_t size; struct sys_info *si; int t[3] = { MR_ATTR_DRAM, MR_ATTR_FLASH, MR_ATTR_SRAM }; int i; if ((si = ub_get_sys_info()) == NULL) panic("could not retrieve system info"); for (i = 0; i < 3; i++) { size = memsize(si, t[i]); if (size > 0) printf("%s: %juMB\n", ub_mem_type(t[i]), (uintmax_t)(size / 1024 / 1024)); } } static const char * get_device_type(const char *devstr, int *devtype) { int i; int namelen; struct device_type *dt; if (devstr) { for (i = 0; i < nitems(device_types); i++) { dt = &device_types[i]; namelen = strlen(dt->name); if (strncmp(dt->name, devstr, namelen) == 0) { *devtype = dt->type; return (devstr + namelen); } } printf("Unknown device type '%s'\n", devstr); } *devtype = -1; return (NULL); } static const char * device_typename(int type) { int i; for (i = 0; i < nitems(device_types); i++) if (device_types[i].type == type) return (device_types[i].name); return (""); } /* * Parse a device string into type, unit, slice and partition numbers. A * returned value of -1 for type indicates a search should be done for the * first loadable device, otherwise a returned value of -1 for unit * indicates a search should be done for the first loadable device of the * given type. * * The returned values for slice and partition are interpreted by * disk_open(). * * Valid device strings: For device types: * * DEV_TYP_STOR, DEV_TYP_NET * DEV_TYP_STOR, DEV_TYP_NET * : DEV_TYP_STOR, DEV_TYP_NET * : DEV_TYP_STOR * :. DEV_TYP_STOR * :. DEV_TYP_STOR * * For valid type names, see the device_types array, above. * * Slice numbers are 1-based. 0 is a wildcard. */ static void get_load_device(int *type, int *unit, int *slice, int *partition) { char *devstr; const char *p; char *endp; *type = -1; *unit = -1; *slice = 0; *partition = -1; devstr = ub_env_get("loaderdev"); if (devstr == NULL) { printf("U-Boot env: loaderdev not set, will probe all devices.\n"); return; } printf("U-Boot env: loaderdev='%s'\n", devstr); p = get_device_type(devstr, type); /* Ignore optional spaces after the device name. */ while (*p == ' ') p++; /* Unknown device name, or a known name without unit number. */ if ((*type == -1) || (*p == '\0')) { return; } /* Malformed unit number. */ if (!isdigit(*p)) { *type = -1; return; } /* Guaranteed to extract a number from the string, as *p is a digit. */ *unit = strtol(p, &endp, 10); p = endp; /* Known device name with unit number and nothing else. */ if (*p == '\0') { return; } /* Device string is malformed beyond unit number. */ if (*p != ':') { *type = -1; *unit = -1; return; } p++; /* No slice and partition specification. */ if ('\0' == *p ) return; /* Only DEV_TYP_STOR devices can have a slice specification. */ if (!(*type & DEV_TYP_STOR)) { *type = -1; *unit = -1; return; } *slice = strtoul(p, &endp, 10); /* Malformed slice number. */ if (p == endp) { *type = -1; *unit = -1; *slice = 0; return; } p = endp; /* No partition specification. */ if (*p == '\0') return; /* Device string is malformed beyond slice number. */ if (*p != '.') { *type = -1; *unit = -1; *slice = 0; return; } p++; /* No partition specification. */ if (*p == '\0') return; *partition = strtol(p, &endp, 10); p = endp; /* Full, valid device string. */ if (*endp == '\0') return; /* Junk beyond partition number. */ *type = -1; *unit = -1; *slice = 0; *partition = -1; } static void print_disk_probe_info() { char slice[32]; char partition[32]; if (currdev.d_disk.slice > 0) sprintf(slice, "%d", currdev.d_disk.slice); else strcpy(slice, ""); if (currdev.d_disk.partition >= 0) sprintf(partition, "%d", currdev.d_disk.partition); else strcpy(partition, ""); printf(" Checking unit=%d slice=%s partition=%s...", currdev.dd.d_unit, slice, partition); } static int probe_disks(int devidx, int load_type, int load_unit, int load_slice, int load_partition) { int open_result, unit; struct open_file f; currdev.d_disk.slice = load_slice; currdev.d_disk.partition = load_partition; f.f_devdata = &currdev; open_result = -1; if (load_type == -1) { printf(" Probing all disk devices...\n"); /* Try each disk in succession until one works. */ for (currdev.dd.d_unit = 0; currdev.dd.d_unit < UB_MAX_DEV; currdev.dd.d_unit++) { print_disk_probe_info(); open_result = devsw[devidx]->dv_open(&f, &currdev); if (open_result == 0) { printf(" good.\n"); return (0); } printf("\n"); } return (-1); } if (load_unit == -1) { printf(" Probing all %s devices...\n", device_typename(load_type)); /* Try each disk of given type in succession until one works. */ for (unit = 0; unit < UB_MAX_DEV; unit++) { currdev.dd.d_unit = uboot_diskgetunit(load_type, unit); if (currdev.dd.d_unit == -1) break; print_disk_probe_info(); open_result = devsw[devidx]->dv_open(&f, &currdev); if (open_result == 0) { printf(" good.\n"); return (0); } printf("\n"); } return (-1); } if ((currdev.dd.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { print_disk_probe_info(); open_result = devsw[devidx]->dv_open(&f,&currdev); if (open_result == 0) { printf(" good.\n"); return (0); } printf("\n"); } printf(" Requested disk type/unit/slice/partition not found\n"); return (-1); } int main(int argc, char **argv) { struct api_signature *sig = NULL; int load_type, load_unit, load_slice, load_partition; int i; const char *ldev; /* * We first check if a command line argument was passed to us containing * API's signature address. If it wasn't then we try to search for the * API signature via the usual hinted address. * If we can't find the magic signature and related info, exit with a * unique error code that U-Boot reports as "## Application terminated, * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to * provide a clue. It's better than 0xffffffff anyway. */ if (!api_parse_cmdline_sig(argc, argv, &sig) && !api_search_sig(&sig)) return (0x01badab1); syscall_ptr = sig->syscall; if (syscall_ptr == NULL) return (0x02badab1); if (sig->version > API_SIG_VERSION) return (0x03badab1); /* Clear BSS sections */ bzero(__sbss_start, __sbss_end - __sbss_start); bzero(__bss_start, _end - __bss_start); /* * Initialise the heap as early as possible. Once this is done, * alloc() is usable. We are using the stack u-boot set up near the top * of physical ram; hopefully there is sufficient space between the end * of our bss and the bottom of the u-boot stack to avoid overlap. */ uboot_heap_start = round_page((uintptr_t)end); uboot_heap_end = uboot_heap_start + HEAP_SIZE; setheap((void *)uboot_heap_start, (void *)uboot_heap_end); /* * Set up console. */ cons_probe(); printf("Compatible U-Boot API signature found @%p\n", sig); printf("\n%s", bootprog_info); printf("\n"); dump_sig(sig); dump_addr_info(); meminfo(); /* * Enumerate U-Boot devices */ if ((devs_no = ub_dev_enum()) == 0) panic("no U-Boot devices found"); printf("Number of U-Boot devices: %d\n", devs_no); get_load_device(&load_type, &load_unit, &load_slice, &load_partition); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_init == NULL) continue; if ((devsw[i]->dv_init)() != 0) continue; printf("Found U-Boot device: %s\n", devsw[i]->dv_name); currdev.dd.d_dev = devsw[i]; currdev.dd.d_unit = 0; if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && strcmp(devsw[i]->dv_name, "disk") == 0) { if (probe_disks(i, load_type, load_unit, load_slice, load_partition) == 0) break; } if ((load_type == -1 || (load_type & DEV_TYP_NET)) && strcmp(devsw[i]->dv_name, "net") == 0) break; } /* * If we couldn't find a boot device, return an error to u-boot. * U-boot may be running a boot script that can try something different * so returning an error is better than forcing a reboot. */ if (devsw[i] == NULL) { printf("No boot device found!\n"); return (0xbadef1ce); } ldev = uboot_fmtdev(&currdev); env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); printf("Booting from %s\n", ldev); setenv("LINES", "24", 1); /* optional */ setenv("prompt", "loader>", 1); archsw.arch_loadaddr = uboot_loadaddr; archsw.arch_getdev = uboot_getdev; archsw.arch_copyin = uboot_copyin; archsw.arch_copyout = uboot_copyout; archsw.arch_readin = uboot_readin; archsw.arch_autoload = uboot_autoload; interact(); /* doesn't return */ return (0); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { printf("heap base at %p, top at %p, used %td\n", end, sbrk(0), sbrk(0) - end); return (CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { printf("Resetting...\n"); ub_reset(); printf("Reset failed!\n"); while (1); __unreachable(); } COMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); static int command_devinfo(int argc, char *argv[]) { int i; if ((devs_no = ub_dev_enum()) == 0) { command_errmsg = "no U-Boot devices found!?"; return (CMD_ERROR); } printf("U-Boot devices:\n"); for (i = 0; i < devs_no; i++) { ub_dump_di(i); printf("\n"); } return (CMD_OK); } COMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); static int command_sysinfo(int argc, char *argv[]) { struct sys_info *si; if ((si = ub_get_sys_info()) == NULL) { command_errmsg = "could not retrieve U-Boot sys info!?"; return (CMD_ERROR); } printf("U-Boot system info:\n"); ub_dump_si(si); return (CMD_OK); } enum ubenv_action { UBENV_UNKNOWN, UBENV_SHOW, UBENV_IMPORT }; static void handle_uboot_env_var(enum ubenv_action action, const char * var) { char ldvar[128]; const char *val; char *wrk; int len; /* * On an import with the variable name formatted as ldname=ubname, * import the uboot variable ubname into the loader variable ldname, * otherwise the historical behavior is to import to uboot.ubname. */ if (action == UBENV_IMPORT) { len = strcspn(var, "="); if (len == 0) { printf("name cannot start with '=': '%s'\n", var); return; } if (var[len] == 0) { strcpy(ldvar, "uboot."); strncat(ldvar, var, sizeof(ldvar) - 7); } else { len = MIN(len, sizeof(ldvar) - 1); strncpy(ldvar, var, len); ldvar[len] = 0; var = &var[len + 1]; } } /* * If the user prepended "uboot." (which is how they usually see these * names) strip it off as a convenience. */ if (strncmp(var, "uboot.", 6) == 0) { var = &var[6]; } /* If there is no variable name left, punt. */ if (var[0] == 0) { printf("empty variable name\n"); return; } val = ub_env_get(var); if (action == UBENV_SHOW) { if (val == NULL) printf("uboot.%s is not set\n", var); else printf("uboot.%s=%s\n", var, val); } else if (action == UBENV_IMPORT) { if (val != NULL) { setenv(ldvar, val, 1); } } } static int command_ubenv(int argc, char *argv[]) { enum ubenv_action action; const char *var; int i; action = UBENV_UNKNOWN; if (argc > 1) { if (strcasecmp(argv[1], "import") == 0) action = UBENV_IMPORT; else if (strcasecmp(argv[1], "show") == 0) action = UBENV_SHOW; } if (action == UBENV_UNKNOWN) { command_errmsg = "usage: 'ubenv [var ...]"; return (CMD_ERROR); } if (argc > 2) { for (i = 2; i < argc; i++) handle_uboot_env_var(action, argv[i]); } else { var = NULL; for (;;) { if ((var = ub_env_enum(var)) == NULL) break; handle_uboot_env_var(action, var); } } return (CMD_OK); } COMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); #ifdef LOADER_FDT_SUPPORT /* * Since proper fdt command handling function is defined in fdt_loader_cmd.c, * and declaring it as extern is in contradiction with COMMAND_SET() macro * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif Index: stable/11/stand/userboot/userboot/main.c =================================================================== --- stable/11/stand/userboot/userboot/main.c (revision 344289) +++ stable/11/stand/userboot/userboot/main.c (revision 344290) @@ -1,238 +1,237 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright (c) 1998,2000 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 "bootstrap.h" #include "disk.h" #include "libuserboot.h" #if defined(USERBOOT_ZFS_SUPPORT) #include "../zfs/libzfs.h" static void userboot_zfs_probe(void); static int userboot_zfs_found; #endif /* Minimum version required */ #define USERBOOT_VERSION USERBOOT_VERSION_3 #define MALLOCSZ (64*1024*1024) struct loader_callbacks *callbacks; void *callbacks_arg; -extern char bootprog_info[]; static jmp_buf jb; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); void delay(int usec) { CALLBACK(delay, usec); } void exit(int v) { CALLBACK(exit, v); longjmp(jb, 1); } void loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks) { static char mallocbuf[MALLOCSZ]; char *var; int i; if (version < USERBOOT_VERSION) abort(); callbacks = cb; callbacks_arg = arg; userboot_disk_maxunit = ndisks; /* * initialise the heap as early as possible. Once this is done, * alloc() is usable. */ setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf))); /* * Hook up the console */ cons_probe(); printf("\n%s", bootprog_info); #if 0 printf("Memory: %ld k\n", memsize() / 1024); #endif setenv("LINES", "24", 1); /* optional */ /* * Set custom environment variables */ i = 0; while (1) { var = CALLBACK(getenv, i++); if (var == NULL) break; putenv(var); } archsw.arch_autoload = userboot_autoload; archsw.arch_getdev = userboot_getdev; archsw.arch_copyin = userboot_copyin; archsw.arch_copyout = userboot_copyout; archsw.arch_readin = userboot_readin; #if defined(USERBOOT_ZFS_SUPPORT) archsw.arch_zfs_probe = userboot_zfs_probe; #endif /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); extract_currdev(); if (setjmp(jb)) return; interact(); /* doesn't return */ exit(0); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. */ static void extract_currdev(void) { struct disk_devdesc dev; //bzero(&dev, sizeof(dev)); #if defined(USERBOOT_ZFS_SUPPORT) if (userboot_zfs_found) { struct zfs_devdesc zdev; /* Leave the pool/root guid's unassigned */ bzero(&zdev, sizeof(zdev)); zdev.dd.d_dev = &zfs_dev; dev = *(struct disk_devdesc *)&zdev; init_zfs_bootenv(zfs_fmtdev(&dev)); } else #endif if (userboot_disk_maxunit > 0) { dev.dd.d_dev = &userboot_disk; dev.dd.d_unit = 0; dev.d_slice = 0; dev.d_partition = 0; /* * If we cannot auto-detect the partition type then * access the disk as a raw device. */ if (dev.dd.d_dev->dv_open(NULL, &dev)) { dev.d_slice = -1; dev.d_partition = -1; } } else { dev.dd.d_dev = &host_dev; dev.dd.d_unit = 0; } env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev), userboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev), env_noset, env_nounset); } #if defined(USERBOOT_ZFS_SUPPORT) static void userboot_zfs_probe(void) { char devname[32]; uint64_t pool_guid; int unit; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. Record if any were found. */ for (unit = 0; unit < userboot_disk_maxunit; unit++) { sprintf(devname, "disk%d:", unit); pool_guid = 0; zfs_probe_dev(devname, &pool_guid); if (pool_guid != 0) userboot_zfs_found = 1; } } #endif COMMAND_SET(quit, "quit", "exit the loader", command_quit); static int command_quit(int argc, char *argv[]) { exit(USERBOOT_EXIT_QUIT); return (CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { exit(USERBOOT_EXIT_REBOOT); return (CMD_OK); } Index: stable/11 =================================================================== --- stable/11 (revision 344289) +++ stable/11 (revision 344290) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r335117