Index: head/sys/boot/common/Makefile.inc =================================================================== --- head/sys/boot/common/Makefile.inc (revision 296181) +++ head/sys/boot/common/Makefile.inc (revision 296182) @@ -1,70 +1,72 @@ # $FreeBSD$ SRCS+= boot.c commands.c console.c devopen.c interp.c SRCS+= interp_backslash.c interp_parse.c ls.c misc.c SRCS+= module.c panic.c .if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c .elif ${MACHINE} == "pc98" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c .elif ${MACHINE_CPUARCH} == "aarch64" SRCS+= load_elf64.c reloc_elf64.c .elif ${MACHINE_CPUARCH} == "arm" SRCS+= load_elf32.c reloc_elf32.c .elif ${MACHINE_CPUARCH} == "powerpc" SRCS+= load_elf32.c reloc_elf32.c SRCS+= load_elf64.c reloc_elf64.c .elif ${MACHINE_CPUARCH} == "sparc64" SRCS+= load_elf64.c reloc_elf64.c .elif ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" SRCS+= load_elf64.c reloc_elf64.c +.elif ${MACHINE_ARCH} == "mips" || ${MACHINE_ARCH} == "mipsel" +SRCS+= load_elf32.c reloc_elf32.c .endif .if defined(LOADER_NET_SUPPORT) SRCS+= dev_net.c .endif .if !defined(LOADER_NO_DISK_SUPPORT) SRCS+= disk.c part.c CFLAGS+= -DLOADER_DISK_SUPPORT .if !defined(LOADER_NO_GPT_SUPPORT) SRCS+= crc32.c CFLAGS+= -DLOADER_GPT_SUPPORT .endif .if !defined(LOADER_NO_MBR_SUPPORT) CFLAGS+= -DLOADER_MBR_SUPPORT .endif .endif .if defined(HAVE_BCACHE) SRCS+= bcache.c .endif .if defined(MD_IMAGE_SIZE) CFLAGS+= -DMD_IMAGE_SIZE=${MD_IMAGE_SIZE} SRCS+= md.c .endif # Machine-independant ISA PnP .if defined(HAVE_ISABUS) SRCS+= isapnp.c .endif .if defined(HAVE_PNP) SRCS+= pnp.c .endif # Forth interpreter .if defined(BOOT_FORTH) SRCS+= interp_forth.c .endif .if defined(BOOT_PROMPT_123) CFLAGS+= -DBOOT_PROMPT_123 .endif .if defined(LOADER_INSTALL_SUPPORT) SRCS+= install.c CFLAGS+=-I${.CURDIR}/../../../../lib/libstand .endif Index: head/sys/boot/common/dev_net.c =================================================================== --- head/sys/boot/common/dev_net.c (revision 296181) +++ head/sys/boot/common/dev_net.c (revision 296182) @@ -1,373 +1,372 @@ /* $NetBSD: dev_net.c,v 1.23 2008/04/28 20:24:06 martin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Gordon W. Ross. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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$"); /*- * This module implements a "raw device" interface suitable for * use by the stand-alone I/O library NFS code. This interface * does not support any "block" access, and exists only for the * purpose of initializing the network interface, getting boot * parameters, and performing the NFS mount. * * At open time, this does: * * find interface - netif_open() * RARP for IP address - rarp_getipaddress() * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) * RPC/mountd - nfs_mount(sock, ip, path) * * the root file handle from mountd is saved in a global * for use by the NFS open code (NFS/lookup). */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dev_net.h" #include "bootstrap.h" #ifdef NETIF_DEBUG int debug = 0; #endif static char *netdev_name; static int netdev_sock = -1; static int netdev_opens; static int net_init(void); static int net_open(struct open_file *, ...); static int net_close(struct open_file *); static void net_cleanup(void); static int net_strategy(); static void net_print(int); static int net_getparams(int sock); struct devsw netdev = { "net", DEVT_NET, net_init, net_strategy, net_open, net_close, noioctl, net_print, net_cleanup }; static int net_init(void) { return (0); } /* * Called by devopen after it sets f->f_dev to our devsw entry. * This opens the low-level device and sets f->f_devdata. * This is declared with variable arguments... */ static int net_open(struct open_file *f, ...) { char temp[FNAME_SIZE]; struct iodesc *d; va_list args; char *devname; /* Device part of file name (or NULL). */ int error = 0; va_start(args, f); devname = va_arg(args, char*); va_end(args); #ifdef NETIF_OPEN_CLOSE_ONCE /* Before opening another interface, close the previous one first. */ if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) net_cleanup(); #endif /* On first open, do netif open, mount, etc. */ if (netdev_opens == 0) { /* Find network interface. */ if (netdev_sock < 0) { netdev_sock = netif_open(devname); if (netdev_sock < 0) { printf("net_open: netif_open() failed\n"); return (ENXIO); } netdev_name = strdup(devname); #ifdef NETIF_DEBUG if (debug) printf("net_open: netif_open() succeeded\n"); #endif } /* * If network params were not set by netif_open(), try to get * them via bootp, rarp, etc. */ if (rootip.s_addr == 0) { /* Get root IP address, and path, etc. */ error = net_getparams(netdev_sock); if (error) { /* getparams makes its own noise */ free(netdev_name); netif_close(netdev_sock); netdev_sock = -1; return (error); } } /* * Set the variables required by the kernel's nfs_diskless * mechanism. This is the minimum set of variables required to * mount a root filesystem without needing to obtain additional * info from bootp or other sources. */ d = socktodesc(netdev_sock); - sprintf(temp, "%6D", d->myea, ":"); - setenv("boot.netif.hwaddr", temp, 1); + setenv("boot.netif.hwaddr", ether_sprintf(d->myea), 1); setenv("boot.netif.ip", inet_ntoa(myip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); } netdev_opens++; f->f_devdata = &netdev_sock; return (error); } static int net_close(struct open_file *f) { #ifdef NETIF_DEBUG if (debug) printf("net_close: opens=%d\n", netdev_opens); #endif f->f_devdata = NULL; #ifndef NETIF_OPEN_CLOSE_ONCE /* Extra close call? */ if (netdev_opens <= 0) return (0); netdev_opens--; /* Not last close? */ if (netdev_opens > 0) return (0); /* On last close, do netif close, etc. */ #ifdef NETIF_DEBUG if (debug) printf("net_close: calling net_cleanup()\n"); #endif net_cleanup(); #endif return (0); } static void net_cleanup(void) { if (netdev_sock >= 0) { #ifdef NETIF_DEBUG if (debug) printf("net_cleanup: calling netif_close()\n"); #endif rootip.s_addr = 0; free(netdev_name); netif_close(netdev_sock); netdev_sock = -1; } } static int net_strategy() { return (EIO); } #define SUPPORT_BOOTP /* * Get info for NFS boot: our IP address, our hostname, * server IP address, and our root path on the server. * There are two ways to do this: The old, Sun way, * and the more modern, BOOTP way. (RFC951, RFC1048) * * The default is to use the Sun bootparams RPC * (because that is what the kernel will do). * MD code can make try_bootp initialied data, * which will override this common definition. */ #ifdef SUPPORT_BOOTP int try_bootp = 1; #endif extern n_long ip_convertaddr(char *p); static int net_getparams(int sock) { char buf[MAXHOSTNAMELEN]; n_long rootaddr, smask; #ifdef SUPPORT_BOOTP /* * Try to get boot info using BOOTP. If we succeed, then * the server IP address, gateway, and root path will all * be initialized. If any remain uninitialized, we will * use RARP and RPC/bootparam (the Sun way) to get them. */ if (try_bootp) bootp(sock, BOOTP_NONE); if (myip.s_addr != 0) goto exit; #ifdef NETIF_DEBUG if (debug) printf("net_open: BOOTP failed, trying RARP/RPC...\n"); #endif #endif /* * Use RARP to get our IP address. This also sets our * netmask to the "natural" default for our address. */ if (rarp_getipaddress(sock)) { printf("net_open: RARP failed\n"); return (EIO); } printf("net_open: client addr: %s\n", inet_ntoa(myip)); /* Get our hostname, server IP address, gateway. */ if (bp_whoami(sock)) { printf("net_open: bootparam/whoami RPC failed\n"); return (EIO); } #ifdef NETIF_DEBUG if (debug) printf("net_open: client name: %s\n", hostname); #endif /* * Ignore the gateway from whoami (unreliable). * Use the "gateway" parameter instead. */ smask = 0; gateip.s_addr = 0; if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { /* Got it! Parse the netmask. */ smask = ip_convertaddr(buf); } if (smask) { netmask = smask; #ifdef NETIF_DEBUG if (debug) printf("net_open: subnet mask: %s\n", intoa(netmask)); #endif } #ifdef NETIF_DEBUG if (gateip.s_addr && debug) printf("net_open: net gateway: %s\n", inet_ntoa(gateip)); #endif /* Get the root server and pathname. */ if (bp_getfile(sock, "root", &rootip, rootpath)) { printf("net_open: bootparam/getfile RPC failed\n"); return (EIO); } exit: if ((rootaddr = net_parse_rootpath()) != INADDR_NONE) rootip.s_addr = rootaddr; #ifdef NETIF_DEBUG if (debug) { printf("net_open: server addr: %s\n", inet_ntoa(rootip)); printf("net_open: server path: %s\n", rootpath); } #endif return (0); } static void net_print(int verbose) { struct netif_driver *drv; int i, d, cnt; cnt = 0; for (d = 0; netif_drivers[d]; d++) { drv = netif_drivers[d]; for (i = 0; i < drv->netif_nifs; i++) { printf("\t%s%d:", "net", cnt++); if (verbose) printf(" (%s%d)", drv->netif_bname, drv->netif_ifs[i].dif_unit); } } printf("\n"); } /* * Strip the server's address off of the rootpath if present and return it in * network byte order, leaving just the pathname part in the global rootpath. */ uint32_t net_parse_rootpath() { int i; n_long addr = INADDR_NONE; for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) if (rootpath[i] == ':') break; if (i && i != FNAME_SIZE && rootpath[i] == ':') { rootpath[i++] = '\0'; addr = inet_addr(&rootpath[0]); bcopy(&rootpath[i], rootpath, strlen(&rootpath[i])+1); } return (addr); } Index: head/sys/boot/fdt/fdt_loader_cmd.c =================================================================== --- head/sys/boot/fdt/fdt_loader_cmd.c (revision 296181) +++ head/sys/boot/fdt/fdt_loader_cmd.c (revision 296182) @@ -1,1576 +1,1578 @@ /*- * Copyright (c) 2009-2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "bootstrap.h" #include "fdt_platform.h" #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif #define FDT_CWD_LEN 256 #define FDT_MAX_DEPTH 6 #define FDT_PROP_SEP " = " #define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) #define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) #define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" #define CMD_REQUIRES_BLOB 0x01 /* Location of FDT yet to be loaded. */ /* This may be in read-only memory, so can't be manipulated directly. */ static struct fdt_header *fdt_to_load = NULL; /* Location of FDT on heap. */ /* This is the copy we actually manipulate. */ static struct fdt_header *fdtp = NULL; /* Size of FDT blob */ static size_t fdtp_size = 0; /* Location of FDT in kernel or module. */ /* This won't be set if FDT is loaded from disk or memory. */ /* If it is set, we'll update it when fdt_copy() gets called. */ static vm_offset_t fdtp_va = 0; static int fdt_load_dtb(vm_offset_t va); static int fdt_cmd_nyi(int argc, char *argv[]); static int fdt_cmd_addr(int argc, char *argv[]); static int fdt_cmd_mkprop(int argc, char *argv[]); static int fdt_cmd_cd(int argc, char *argv[]); static int fdt_cmd_hdr(int argc, char *argv[]); static int fdt_cmd_ls(int argc, char *argv[]); static int fdt_cmd_prop(int argc, char *argv[]); static int fdt_cmd_pwd(int argc, char *argv[]); static int fdt_cmd_rm(int argc, char *argv[]); static int fdt_cmd_mknode(int argc, char *argv[]); static int fdt_cmd_mres(int argc, char *argv[]); typedef int cmdf_t(int, char *[]); struct cmdtab { const char *name; cmdf_t *handler; int flags; }; static const struct cmdtab commands[] = { { "addr", &fdt_cmd_addr, 0 }, { "alias", &fdt_cmd_nyi, 0 }, { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, { NULL, NULL } }; static char cwd[FDT_CWD_LEN] = "/"; static vm_offset_t fdt_find_static_dtb() { Elf_Ehdr *ehdr; Elf_Shdr *shdr; Elf_Sym sym; vm_offset_t strtab, symtab, fdt_start; uint64_t offs; struct preloaded_file *kfp; struct file_metadata *md; char *strp; int i, sym_count; debugf("fdt_find_static_dtb()\n"); sym_count = symtab = strtab = 0; strp = NULL; offs = __elfN(relocation_offset); kfp = file_findfile(NULL, NULL); if (kfp == NULL) return (0); /* Locate the dynamic symbols and strtab. */ md = file_findmetadata(kfp, MODINFOMD_ELFHDR); if (md == NULL) return (0); ehdr = (Elf_Ehdr *)md->md_data; md = file_findmetadata(kfp, MODINFOMD_SHDR); if (md == NULL) return (0); shdr = (Elf_Shdr *)md->md_data; for (i = 0; i < ehdr->e_shnum; ++i) { if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { symtab = shdr[i].sh_addr + offs; sym_count = shdr[i].sh_size / sizeof(Elf_Sym); } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { strtab = shdr[i].sh_addr + offs; } } /* * The most efficent way to find a symbol would be to calculate a * hash, find proper bucket and chain, and thus find a symbol. * However, that would involve code duplication (e.g. for hash * function). So we're using simpler and a bit slower way: we're * iterating through symbols, searching for the one which name is * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, * we are eliminating symbols type of which is not STT_NOTYPE, or(and) * those which binding attribute is not STB_GLOBAL. */ fdt_start = 0; while (sym_count > 0 && fdt_start == 0) { COPYOUT(symtab, &sym, sizeof(sym)); symtab += sizeof(sym); --sym_count; if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) continue; strp = strdupout(strtab + sym.st_name); if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) fdt_start = (vm_offset_t)sym.st_value + offs; free(strp); } return (fdt_start); } static int fdt_load_dtb(vm_offset_t va) { struct fdt_header header; int err; debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); COPYOUT(va, &header, sizeof(header)); err = fdt_check_header(&header); if (err < 0) { if (err == -FDT_ERR_BADVERSION) sprintf(command_errbuf, "incompatible blob version: %d, should be: %d", fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); else sprintf(command_errbuf, "error validating blob: %s", fdt_strerror(err)); return (1); } /* * Release previous blob */ if (fdtp) free(fdtp); fdtp_size = fdt_totalsize(&header); fdtp = malloc(fdtp_size); if (fdtp == NULL) { command_errmsg = "can't allocate memory for device tree copy"; return (1); } fdtp_va = va; COPYOUT(va, fdtp, fdtp_size); debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); return (0); } int fdt_load_dtb_addr(struct fdt_header *header) { int err; debugf("fdt_load_dtb_addr(%p)\n", header); fdtp_size = fdt_totalsize(header); err = fdt_check_header(header); if (err < 0) { sprintf(command_errbuf, "error validating blob: %s", fdt_strerror(err)); return (err); } free(fdtp); if ((fdtp = malloc(fdtp_size)) == NULL) { command_errmsg = "can't allocate memory for device tree copy"; return (1); } fdtp_va = 0; // Don't write this back into module or kernel. bcopy(header, fdtp, fdtp_size); return (0); } int fdt_load_dtb_file(const char * filename) { struct preloaded_file *bfp, *oldbfp; int err; debugf("fdt_load_dtb_file(%s)\n", filename); oldbfp = file_findfile(NULL, "dtb"); /* Attempt to load and validate a new dtb from a file. */ if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) { sprintf(command_errbuf, "failed to load file '%s'", filename); return (1); } if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { file_discard(bfp); return (err); } /* A new dtb was validated, discard any previous file. */ if (oldbfp) file_discard(oldbfp); return (0); } int fdt_setup_fdtp() { struct preloaded_file *bfp; vm_offset_t va; debugf("fdt_setup_fdtp()\n"); /* If we already loaded a file, use it. */ if ((bfp = file_findfile(NULL, "dtb")) != NULL) { if (fdt_load_dtb(bfp->f_addr) == 0) { printf("Using DTB from loaded file '%s'.\n", bfp->f_name); return (0); } } /* If we were given the address of a valid blob in memory, use it. */ if (fdt_to_load != NULL) { if (fdt_load_dtb_addr(fdt_to_load) == 0) { - printf("Using DTB from memory address 0x%08X.\n", - (unsigned int)fdt_to_load); + printf("Using DTB from memory address 0x%p.\n", + fdt_to_load); return (0); } } if (fdt_platform_load_dtb() == 0) return (0); /* If there is a dtb compiled into the kernel, use it. */ if ((va = fdt_find_static_dtb()) != 0) { if (fdt_load_dtb(va) == 0) { printf("Using DTB compiled into kernel.\n"); return (0); } } command_errmsg = "No device tree blob found!\n"; return (1); } #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ (cellbuf), (lim), (cellsize), 0); /* Force using base 16 */ #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ (cellbuf), (lim), (cellsize), 16); static int _fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize, uint8_t base) { const char *buf = str; const char *end = str + strlen(str) - 2; uint32_t *u32buf = NULL; uint8_t *u8buf = NULL; int cnt = 0; if (cellsize == sizeof(uint32_t)) u32buf = (uint32_t *)cellbuf; else u8buf = (uint8_t *)cellbuf; if (lim == 0) return (0); while (buf < end) { /* Skip white whitespace(s)/separators */ while (!isxdigit(*buf) && buf < end) buf++; if (u32buf != NULL) u32buf[cnt] = cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); else u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); if (cnt + 1 <= lim - 1) cnt++; else break; buf++; /* Find another number */ while ((isxdigit(*buf) || *buf == 'x') && buf < end) buf++; } return (cnt); } void fdt_fixup_ethernet(const char *str, char *ethstr, int len) { uint8_t tmp_addr[6]; /* Convert macaddr string into a vector of uints */ fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); /* Set actual property to a value from vect */ fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); } void fdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) { int lo, o = 0, o2, maxo = 0, depth; const uint32_t zero = 0; /* We want to modify every subnode of /cpus */ o = fdt_path_offset(fdtp, "/cpus"); if (o < 0) return; /* maxo should contain offset of node next to /cpus */ depth = 0; maxo = o; while (depth != -1) maxo = fdt_next_node(fdtp, maxo, &depth); /* Find CPU frequency properties */ o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", &zero, sizeof(uint32_t)); o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, sizeof(uint32_t)); lo = MIN(o, o2); while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { o = fdt_node_offset_by_prop_value(fdtp, lo, "clock-frequency", &zero, sizeof(uint32_t)); o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", &zero, sizeof(uint32_t)); /* We're only interested in /cpus subnode(s) */ if (lo > maxo) break; fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", (uint32_t)cpufreq); fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", (uint32_t)busfreq); lo = MIN(o, o2); } } +#ifdef notyet static int fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) { int cells_in_tuple, i, tuples, tuple_size; uint32_t cur_start, cur_size; cells_in_tuple = (addr_cells + size_cells); tuple_size = cells_in_tuple * sizeof(uint32_t); tuples = len / tuple_size; if (tuples == 0) return (EINVAL); for (i = 0; i < tuples; i++) { if (addr_cells == 2) cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); else cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); if (size_cells == 2) cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); else cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); if (cur_size == 0) return (EINVAL); debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", i, cur_start, cur_size); } return (0); } +#endif void fdt_fixup_memory(struct fdt_mem_region *region, size_t num) { struct fdt_mem_region *curmr; uint32_t addr_cells, size_cells; uint32_t *addr_cellsp, *size_cellsp; int err, i, len, memory, root; size_t realmrno; uint8_t *buf, *sb; uint64_t rstart, rsize; int reserved; root = fdt_path_offset(fdtp, "/"); if (root < 0) { sprintf(command_errbuf, "Could not find root node !"); return; } memory = fdt_path_offset(fdtp, "/memory"); if (memory <= 0) { /* Create proper '/memory' node. */ memory = fdt_add_subnode(fdtp, root, "memory"); if (memory <= 0) { sprintf(command_errbuf, "Could not fixup '/memory' " "node, error code : %d!\n", memory); return; } err = fdt_setprop(fdtp, memory, "device_type", "memory", sizeof("memory")); if (err < 0) return; } addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", NULL); size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); if (addr_cellsp == NULL || size_cellsp == NULL) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "%s %s property not found in root node!\n", (!addr_cellsp) ? "#address-cells" : "", (!size_cellsp) ? "#size-cells" : ""); return; } addr_cells = fdt32_to_cpu(*addr_cellsp); size_cells = fdt32_to_cpu(*size_cellsp); /* * Convert memreserve data to memreserve property * Check if property already exists */ reserved = fdt_num_mem_rsv(fdtp); if (reserved && (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < reserved; i++) { if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) break; if (rsize) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(rstart); else *(uint32_t *)buf = cpu_to_fdt32(rstart); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(rsize); else *(uint32_t *)buf = cpu_to_fdt32(rsize); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) printf("Could not fixup 'memreserve' property.\n"); free(sb); } /* Count valid memory regions entries in sysinfo. */ realmrno = num; for (i = 0; i < num; i++) if (region[i].start == 0 && region[i].size == 0) realmrno--; if (realmrno == 0) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "sysinfo doesn't contain valid memory regions info!\n"); return; } len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < num; i++) { curmr = ®ion[i]; if (curmr->size != 0) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->start); else *(uint32_t *)buf = cpu_to_fdt32(curmr->start); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->size); else *(uint32_t *)buf = cpu_to_fdt32(curmr->size); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); free(sb); } void fdt_fixup_stdout(const char *str) { char *ptr; int serialno; int len, no, sero; const struct fdt_property *prop; char *tmp[10]; ptr = (char *)str + strlen(str) - 1; while (ptr > str && isdigit(*(str - 1))) str--; if (ptr == str) return; serialno = (int)strtol(ptr, NULL, 0); no = fdt_path_offset(fdtp, "/chosen"); if (no < 0) return; prop = fdt_get_property(fdtp, no, "stdout", &len); /* If /chosen/stdout does not extist, create it */ if (prop == NULL || (prop != NULL && len == 0)) { bzero(tmp, 10 * sizeof(char)); strcpy((char *)&tmp, "serial"); if (strlen(ptr) > 3) /* Serial number too long */ return; strncpy((char *)tmp + 6, ptr, 3); sero = fdt_path_offset(fdtp, (const char *)tmp); if (sero < 0) /* * If serial device we're trying to assign * stdout to doesn't exist in DT -- return. */ return; fdt_setprop(fdtp, no, "stdout", &tmp, strlen((char *)&tmp) + 1); fdt_setprop(fdtp, no, "stdin", &tmp, strlen((char *)&tmp) + 1); } } /* * Locate the blob, fix it up and return its location. */ static int fdt_fixup(void) { int chosen, len; len = 0; debugf("fdt_fixup()\n"); if (fdtp == NULL && fdt_setup_fdtp() != 0) return (0); /* Create /chosen node (if not exists) */ if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == -FDT_ERR_NOTFOUND) chosen = fdt_add_subnode(fdtp, 0, "chosen"); /* Value assigned to fixup-applied does not matter. */ if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) return (1); fdt_platform_fixups(); fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); return (1); } /* * Copy DTB blob to specified location and return size */ int fdt_copy(vm_offset_t va) { int err; debugf("fdt_copy va 0x%08x\n", va); if (fdtp == NULL) { err = fdt_setup_fdtp(); if (err) { printf("No valid device tree blob found!\n"); return (0); } } if (fdt_fixup() == 0) return (0); if (fdtp_va != 0) { /* Overwrite the FDT with the fixed version. */ /* XXX Is this really appropriate? */ COPYIN(fdtp, fdtp_va, fdtp_size); } COPYIN(fdtp, va, fdtp_size); return (fdtp_size); } int command_fdt_internal(int argc, char *argv[]) { cmdf_t *cmdh; int flags; char *cmd; int i, err; if (argc < 2) { command_errmsg = "usage is 'fdt []"; return (CMD_ERROR); } /* * Validate fdt . */ cmd = strdup(argv[1]); i = 0; cmdh = NULL; while (!(commands[i].name == NULL)) { if (strcmp(cmd, commands[i].name) == 0) { /* found it */ cmdh = commands[i].handler; flags = commands[i].flags; break; } i++; } if (cmdh == NULL) { command_errmsg = "unknown command"; return (CMD_ERROR); } if (flags & CMD_REQUIRES_BLOB) { /* * Check if uboot env vars were parsed already. If not, do it now. */ if (fdt_fixup() == 0) return (CMD_ERROR); } /* * Call command handler. */ err = (*cmdh)(argc, argv); return (err); } static int fdt_cmd_addr(int argc, char *argv[]) { struct preloaded_file *fp; struct fdt_header *hdr; const char *addr; char *cp; fdt_to_load = NULL; if (argc > 2) addr = argv[2]; else { sprintf(command_errbuf, "no address specified"); return (CMD_ERROR); } hdr = (struct fdt_header *)strtoul(addr, &cp, 16); if (cp == addr) { sprintf(command_errbuf, "Invalid address: %s", addr); return (CMD_ERROR); } while ((fp = file_findfile(NULL, "dtb")) != NULL) { file_discard(fp); } fdt_to_load = hdr; return (CMD_OK); } static int fdt_cmd_cd(int argc, char *argv[]) { char *path; char tmp[FDT_CWD_LEN]; int len, o; path = (argc > 2) ? argv[2] : "/"; if (path[0] == '/') { len = strlen(path); if (len >= FDT_CWD_LEN) goto fail; } else { /* Handle path specification relative to cwd */ len = strlen(cwd) + strlen(path) + 1; if (len >= FDT_CWD_LEN) goto fail; strcpy(tmp, cwd); strcat(tmp, "/"); strcat(tmp, path); path = tmp; } o = fdt_path_offset(fdtp, path); if (o < 0) { sprintf(command_errbuf, "could not find node: '%s'", path); return (CMD_ERROR); } strcpy(cwd, path); return (CMD_OK); fail: sprintf(command_errbuf, "path too long: %d, max allowed: %d", len, FDT_CWD_LEN - 1); return (CMD_ERROR); } static int fdt_cmd_hdr(int argc __unused, char *argv[] __unused) { char line[80]; int ver; if (fdtp == NULL) { command_errmsg = "no device tree blob pointer?!"; return (CMD_ERROR); } ver = fdt_version(fdtp); pager_open(); sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); pager_output(line); sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); pager_output(line); sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); pager_output(line); sprintf(line, " off_dt_struct = 0x%08x\n", fdt_off_dt_struct(fdtp)); pager_output(line); sprintf(line, " off_dt_strings = 0x%08x\n", fdt_off_dt_strings(fdtp)); pager_output(line); sprintf(line, " off_mem_rsvmap = 0x%08x\n", fdt_off_mem_rsvmap(fdtp)); pager_output(line); sprintf(line, " version = %d\n", ver); pager_output(line); sprintf(line, " last compatible version = %d\n", fdt_last_comp_version(fdtp)); pager_output(line); if (ver >= 2) { sprintf(line, " boot_cpuid = %d\n", fdt_boot_cpuid_phys(fdtp)); pager_output(line); } if (ver >= 3) { sprintf(line, " size_dt_strings = %d\n", fdt_size_dt_strings(fdtp)); pager_output(line); } if (ver >= 17) { sprintf(line, " size_dt_struct = %d\n", fdt_size_dt_struct(fdtp)); pager_output(line); } pager_close(); return (CMD_OK); } static int fdt_cmd_ls(int argc, char *argv[]) { const char *prevname[FDT_MAX_DEPTH] = { NULL }; const char *name; char *path; int i, o, depth, len; path = (argc > 2) ? argv[2] : NULL; if (path == NULL) path = cwd; o = fdt_path_offset(fdtp, path); if (o < 0) { sprintf(command_errbuf, "could not find node: '%s'", path); return (CMD_ERROR); } for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) { name = fdt_get_name(fdtp, o, &len); if (depth > FDT_MAX_DEPTH) { printf("max depth exceeded: %d\n", depth); continue; } prevname[depth] = name; /* Skip root (i = 1) when printing devices */ for (i = 1; i <= depth; i++) { if (prevname[i] == NULL) break; if (strcmp(cwd, "/") == 0) printf("/"); printf("%s", prevname[i]); } printf("\n"); } return (CMD_OK); } static __inline int isprint(int c) { return (c >= ' ' && c <= 0x7e); } static int fdt_isprint(const void *data, int len, int *count) { const char *d; char ch; int yesno, i; if (len == 0) return (0); d = (const char *)data; if (d[len - 1] != '\0') return (0); *count = 0; yesno = 1; for (i = 0; i < len; i++) { ch = *(d + i); if (isprint(ch) || (ch == '\0' && i > 0)) { /* Count strings */ if (ch == '\0') (*count)++; continue; } yesno = 0; break; } return (yesno); } static int fdt_data_str(const void *data, int len, int count, char **buf) { char *b, *tmp; const char *d; int buf_len, i, l; /* * Calculate the length for the string and allocate memory. * * Note that 'len' already includes at least one terminator. */ buf_len = len; if (count > 1) { /* * Each token had already a terminator buried in 'len', but we * only need one eventually, don't count space for these. */ buf_len -= count - 1; /* Each consecutive token requires a ", " separator. */ buf_len += count * 2; } /* Add some space for surrounding double quotes. */ buf_len += count * 2; /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ b = (char *)malloc(buf_len); tmp = (char *)malloc(buf_len); if (b == NULL) goto error; if (tmp == NULL) { free(b); goto error; } b[0] = '\0'; /* * Now that we have space, format the string. */ i = 0; do { d = (const char *)data + i; l = strlen(d) + 1; sprintf(tmp, "\"%s\"%s", d, (i + l) < len ? ", " : ""); strcat(b, tmp); i += l; } while (i < len); *buf = b; free(tmp); return (0); error: return (1); } static int fdt_data_cell(const void *data, int len, char **buf) { char *b, *tmp; const uint32_t *c; int count, i, l; /* Number of cells */ count = len / 4; /* * Calculate the length for the string and allocate memory. */ /* Each byte translates to 2 output characters */ l = len * 2; if (count > 1) { /* Each consecutive cell requires a " " separator. */ l += (count - 1) * 1; } /* Each cell will have a "0x" prefix */ l += count * 2; /* Space for surrounding <> and terminator */ l += 3; b = (char *)malloc(l); tmp = (char *)malloc(l); if (b == NULL) goto error; if (tmp == NULL) { free(b); goto error; } b[0] = '\0'; strcat(b, "<"); for (i = 0; i < len; i += 4) { c = (const uint32_t *)((const uint8_t *)data + i); sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), i < (len - 4) ? " " : ""); strcat(b, tmp); } strcat(b, ">"); *buf = b; free(tmp); return (0); error: return (1); } static int fdt_data_bytes(const void *data, int len, char **buf) { char *b, *tmp; const char *d; int i, l; /* * Calculate the length for the string and allocate memory. */ /* Each byte translates to 2 output characters */ l = len * 2; if (len > 1) /* Each consecutive byte requires a " " separator. */ l += (len - 1) * 1; /* Each byte will have a "0x" prefix */ l += len * 2; /* Space for surrounding [] and terminator. */ l += 3; b = (char *)malloc(l); tmp = (char *)malloc(l); if (b == NULL) goto error; if (tmp == NULL) { free(b); goto error; } b[0] = '\0'; strcat(b, "["); for (i = 0, d = data; i < len; i++) { sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); strcat(b, tmp); } strcat(b, "]"); *buf = b; free(tmp); return (0); error: return (1); } static int fdt_data_fmt(const void *data, int len, char **buf) { int count; if (len == 0) { *buf = NULL; return (1); } if (fdt_isprint(data, len, &count)) return (fdt_data_str(data, len, count, buf)); else if ((len % 4) == 0) return (fdt_data_cell(data, len, buf)); else return (fdt_data_bytes(data, len, buf)); } static int fdt_prop(int offset) { char *line, *buf; const struct fdt_property *prop; const char *name; const void *data; int len, rv; line = NULL; prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); if (prop == NULL) return (1); name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); len = fdt32_to_cpu(prop->len); rv = 0; buf = NULL; if (len == 0) { /* Property without value */ line = (char *)malloc(strlen(name) + 2); if (line == NULL) { rv = 2; goto out2; } sprintf(line, "%s\n", name); goto out1; } /* * Process property with value */ data = prop->data; if (fdt_data_fmt(data, len, &buf) != 0) { rv = 3; goto out2; } line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + strlen(buf) + 2); if (line == NULL) { sprintf(command_errbuf, "could not allocate space for string"); rv = 4; goto out2; } sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); out1: pager_open(); pager_output(line); pager_close(); out2: if (buf) free(buf); if (line) free(line); return (rv); } static int fdt_modprop(int nodeoff, char *propname, void *value, char mode) { uint32_t cells[100]; const char *buf; int len, rv; const struct fdt_property *p; p = fdt_get_property(fdtp, nodeoff, propname, NULL); if (p != NULL) { if (mode == 1) { /* Adding inexistant value in mode 1 is forbidden */ sprintf(command_errbuf, "property already exists!"); return (CMD_ERROR); } } else if (mode == 0) { sprintf(command_errbuf, "property does not exist!"); return (CMD_ERROR); } len = strlen(value); rv = 0; buf = value; switch (*buf) { case '&': /* phandles */ break; case '<': /* Data cells */ len = fdt_strtovect(buf, (void *)&cells, 100, sizeof(uint32_t)); rv = fdt_setprop(fdtp, nodeoff, propname, &cells, len * sizeof(uint32_t)); break; case '[': /* Data bytes */ len = fdt_strtovect(buf, (void *)&cells, 100, sizeof(uint8_t)); rv = fdt_setprop(fdtp, nodeoff, propname, &cells, len * sizeof(uint8_t)); break; case '"': default: /* Default -- string */ rv = fdt_setprop_string(fdtp, nodeoff, propname, value); break; } if (rv != 0) { if (rv == -FDT_ERR_NOSPACE) sprintf(command_errbuf, "Device tree blob is too small!\n"); else sprintf(command_errbuf, "Could not add/modify property!\n"); } return (rv); } /* Merge strings from argv into a single string */ static int fdt_merge_strings(int argc, char *argv[], int start, char **buffer) { char *buf; int i, idx, sz; *buffer = NULL; sz = 0; for (i = start; i < argc; i++) sz += strlen(argv[i]); /* Additional bytes for whitespaces between args */ sz += argc - start; buf = (char *)malloc(sizeof(char) * sz); if (buf == NULL) { sprintf(command_errbuf, "could not allocate space " "for string"); return (1); } bzero(buf, sizeof(char) * sz); idx = 0; for (i = start, idx = 0; i < argc; i++) { strcpy(buf + idx, argv[i]); idx += strlen(argv[i]); buf[idx] = ' '; idx++; } buf[sz - 1] = '\0'; *buffer = buf; return (0); } /* Extract offset and name of node/property from a given path */ static int fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) { int o; char *path = *pathp, *name = NULL, *subpath = NULL; subpath = strrchr(path, '/'); if (subpath == NULL) { o = fdt_path_offset(fdtp, cwd); name = path; path = (char *)&cwd; } else { *subpath = '\0'; if (strlen(path) == 0) path = cwd; name = subpath + 1; o = fdt_path_offset(fdtp, path); } if (strlen(name) == 0) { sprintf(command_errbuf, "name not specified"); return (1); } if (o < 0) { sprintf(command_errbuf, "could not find node: '%s'", path); return (1); } *namep = name; *nodeoff = o; *pathp = path; return (0); } static int fdt_cmd_prop(int argc, char *argv[]) { char *path, *propname, *value; int o, next, depth, rv; uint32_t tag; path = (argc > 2) ? argv[2] : NULL; value = NULL; if (argc > 3) { /* Merge property value strings into one */ if (fdt_merge_strings(argc, argv, 3, &value) != 0) return (CMD_ERROR); } else value = NULL; if (path == NULL) path = cwd; rv = CMD_OK; if (value) { /* If value is specified -- try to modify prop. */ if (fdt_extract_nameloc(&path, &propname, &o) != 0) return (CMD_ERROR); rv = fdt_modprop(o, propname, value, 0); if (rv) return (CMD_ERROR); return (CMD_OK); } /* User wants to display properties */ o = fdt_path_offset(fdtp, path); if (o < 0) { sprintf(command_errbuf, "could not find node: '%s'", path); rv = CMD_ERROR; goto out; } depth = 0; while (depth >= 0) { tag = fdt_next_tag(fdtp, o, &next); switch (tag) { case FDT_NOP: break; case FDT_PROP: if (depth > 1) /* Don't process properties of nested nodes */ break; if (fdt_prop(o) != 0) { sprintf(command_errbuf, "could not process " "property"); rv = CMD_ERROR; goto out; } break; case FDT_BEGIN_NODE: depth++; if (depth > FDT_MAX_DEPTH) { printf("warning: nesting too deep: %d\n", depth); goto out; } break; case FDT_END_NODE: depth--; if (depth == 0) /* * This is the end of our starting node, force * the loop finish. */ depth--; break; } o = next; } out: return (rv); } static int fdt_cmd_mkprop(int argc, char *argv[]) { int o; char *path, *propname, *value; path = (argc > 2) ? argv[2] : NULL; value = NULL; if (argc > 3) { /* Merge property value strings into one */ if (fdt_merge_strings(argc, argv, 3, &value) != 0) return (CMD_ERROR); } else value = NULL; if (fdt_extract_nameloc(&path, &propname, &o) != 0) return (CMD_ERROR); if (fdt_modprop(o, propname, value, 1)) return (CMD_ERROR); return (CMD_OK); } static int fdt_cmd_rm(int argc, char *argv[]) { int o, rv; char *path = NULL, *propname; if (argc > 2) path = argv[2]; else { sprintf(command_errbuf, "no node/property name specified"); return (CMD_ERROR); } o = fdt_path_offset(fdtp, path); if (o < 0) { /* If node not found -- try to find & delete property */ if (fdt_extract_nameloc(&path, &propname, &o) != 0) return (CMD_ERROR); if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { sprintf(command_errbuf, "could not delete" "%s\n", (rv == -FDT_ERR_NOTFOUND) ? "(property/node does not exist)" : ""); return (CMD_ERROR); } else return (CMD_OK); } /* If node exists -- remove node */ rv = fdt_del_node(fdtp, o); if (rv) { sprintf(command_errbuf, "could not delete node"); return (CMD_ERROR); } return (CMD_OK); } static int fdt_cmd_mknode(int argc, char *argv[]) { int o, rv; char *path = NULL, *nodename = NULL; if (argc > 2) path = argv[2]; else { sprintf(command_errbuf, "no node name specified"); return (CMD_ERROR); } if (fdt_extract_nameloc(&path, &nodename, &o) != 0) return (CMD_ERROR); rv = fdt_add_subnode(fdtp, o, nodename); if (rv < 0) { if (rv == -FDT_ERR_NOSPACE) sprintf(command_errbuf, "Device tree blob is too small!\n"); else sprintf(command_errbuf, "Could not add node!\n"); return (CMD_ERROR); } return (CMD_OK); } static int fdt_cmd_pwd(int argc, char *argv[]) { char line[FDT_CWD_LEN]; pager_open(); sprintf(line, "%s\n", cwd); pager_output(line); pager_close(); return (CMD_OK); } static int fdt_cmd_mres(int argc, char *argv[]) { uint64_t start, size; int i, total; char line[80]; pager_open(); total = fdt_num_mem_rsv(fdtp); if (total > 0) { pager_output("Reserved memory regions:\n"); for (i = 0; i < total; i++) { fdt_get_mem_rsv(fdtp, i, &start, &size); sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", i, start, size); pager_output(line); } } else pager_output("No reserved memory regions\n"); pager_close(); return (CMD_OK); } static int fdt_cmd_nyi(int argc, char *argv[]) { printf("command not yet implemented\n"); return (CMD_ERROR); } Index: head/sys/boot/uboot/common/main.c =================================================================== --- head/sys/boot/uboot/common/main.c (revision 296181) +++ head/sys/boot/uboot/common/main.c (revision 296182) @@ -1,680 +1,680 @@ /*- * 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 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_name[]; extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; 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: %lldMB\n", ub_mem_type(t[i]), - size / 1024 / 1024); + 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.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.d_unit = 0; currdev.d_unit < UB_MAX_DEV; currdev.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.d_unit = uboot_diskgetunit(load_type, unit); if (currdev.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.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(void) { struct api_signature *sig = NULL; int load_type, load_unit, load_slice, load_partition; int i; const char *ldev; /* * 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_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. The stack is buried inside us, so this is safe. */ uboot_heap_start = round_page((uintptr_t)end); uboot_heap_end = uboot_heap_start + 512 * 1024; setheap((void *)uboot_heap_start, (void *)uboot_heap_end); /* * Set up console. */ cons_probe(); - printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig); + printf("Compatible U-Boot API signature found @%p\n", sig); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); 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.d_dev = devsw[i]; currdev.d_type = currdev.d_dev->dv_type; currdev.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(NULL); /* 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 %d\n", end, sbrk(0), + 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); } 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: head/sys/boot/uboot/lib/disk.c =================================================================== --- head/sys/boot/uboot/lib/disk.c (revision 296181) +++ head/sys/boot/uboot/lib/disk.c (revision 296182) @@ -1,303 +1,304 @@ /*- * Copyright (c) 2008 Semihalf, Rafal Jaworowski * Copyright (c) 2009 Semihalf, Piotr Ziecik * Copyright (c) 2012 Andrey V. Elsukov * 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. * */ /* * Block storage I/O routines for U-Boot */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "api_public.h" #include "bootstrap.h" #include "disk.h" #include "glue.h" #include "libuboot.h" #define stor_printf(fmt, args...) do { \ printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ printf(fmt, ##args); \ } while (0) #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif static struct { int opened; /* device is opened */ int handle; /* storage device handle */ int type; /* storage type */ off_t blocks; /* block count */ u_int bsize; /* block size */ } stor_info[UB_MAX_DEV]; #define SI(dev) (stor_info[(dev)->d_unit]) static int stor_info_no = 0; static int stor_opendev(struct disk_devdesc *); static int stor_readdev(struct disk_devdesc *, daddr_t, size_t, char *); /* devsw I/F */ static int stor_init(void); static int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int stor_open(struct open_file *, ...); static int stor_close(struct open_file *); static int stor_ioctl(struct open_file *f, u_long cmd, void *data); static void stor_print(int); static void stor_cleanup(void); struct devsw uboot_storage = { "disk", DEVT_DISK, stor_init, stor_strategy, stor_open, stor_close, stor_ioctl, stor_print, stor_cleanup }; static int stor_init(void) { struct device_info *di; int i; if (devs_no == 0) { printf("No U-Boot devices! Really enumerated?\n"); return (-1); } for (i = 0; i < devs_no; i++) { di = ub_dev_get(i); if ((di != NULL) && (di->type & DEV_TYP_STOR)) { if (stor_info_no >= UB_MAX_DEV) { printf("Too many storage devices: %d\n", stor_info_no); return (-1); } stor_info[stor_info_no].handle = i; stor_info[stor_info_no].opened = 0; stor_info[stor_info_no].type = di->type; stor_info[stor_info_no].blocks = di->di_stor.block_count; stor_info[stor_info_no].bsize = di->di_stor.block_size; stor_info_no++; } } if (!stor_info_no) { debugf("No storage devices\n"); return (-1); } debugf("storage devices found: %d\n", stor_info_no); return (0); } static void stor_cleanup(void) { int i; for (i = 0; i < stor_info_no; i++) if (stor_info[i].opened > 0) ub_dev_close(stor_info[i].handle); disk_cleanup(&uboot_storage); } static int stor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; daddr_t bcount; int err; if (rw != F_READ) { stor_printf("write attempt, operation not supported!\n"); return (EROFS); } if (size % SI(dev).bsize) { - stor_printf("size=%d not multiple of device block size=%d\n", + stor_printf("size=%zu not multiple of device " + "block size=%d\n", size, SI(dev).bsize); return (EIO); } bcount = size / SI(dev).bsize; if (rsize) *rsize = 0; err = stor_readdev(dev, blk + dev->d_offset, bcount, buf); if (!err && rsize) *rsize = size; return (err); } static int stor_open(struct open_file *f, ...) { va_list ap; struct disk_devdesc *dev; va_start(ap, f); dev = va_arg(ap, struct disk_devdesc *); va_end(ap); return (stor_opendev(dev)); } static int stor_opendev(struct disk_devdesc *dev) { int err; if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) return (EIO); if (SI(dev).opened == 0) { err = ub_dev_open(SI(dev).handle); if (err != 0) { stor_printf("device open failed with error=%d, " "handle=%d\n", err, SI(dev).handle); return (ENXIO); } SI(dev).opened++; } return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, SI(dev).bsize, 0)); } static int stor_close(struct open_file *f) { struct disk_devdesc *dev; dev = (struct disk_devdesc *)(f->f_devdata); return (disk_close(dev)); } static int stor_readdev(struct disk_devdesc *dev, daddr_t blk, size_t size, char *buf) { lbasize_t real_size; int err; debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf); err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size); if (err != 0) { stor_printf("read failed, error=%d\n", err); return (EIO); } if (real_size != size) { stor_printf("real size != size\n"); err = EIO; } return (err); } static void stor_print(int verbose) { struct disk_devdesc dev; static char line[80]; int i; for (i = 0; i < stor_info_no; i++) { dev.d_dev = &uboot_storage; dev.d_unit = i; dev.d_slice = -1; dev.d_partition = -1; sprintf(line, "\tdisk%d (%s)\n", i, ub_stor_type(SI(&dev).type)); pager_output(line); if (stor_opendev(&dev) == 0) { sprintf(line, "\tdisk%d", i); disk_print(&dev, line, verbose); disk_close(&dev); } } } static int stor_ioctl(struct open_file *f, u_long cmd, void *data) { struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = SI(dev).bsize; break; case DIOCGMEDIASIZE: *(off_t *)data = SI(dev).bsize * SI(dev).blocks; break; default: return (ENOTTY); } return (0); } /* * Return the device unit number for the given type and type-relative unit * number. */ int uboot_diskgetunit(int type, int type_unit) { int local_type_unit; int i; local_type_unit = 0; for (i = 0; i < stor_info_no; i++) { if ((stor_info[i].type & type) == type) { if (local_type_unit == type_unit) { return (i); } local_type_unit++; } } return (-1); } Index: head/sys/boot/uboot/lib/elf_freebsd.c =================================================================== --- head/sys/boot/uboot/lib/elf_freebsd.c (revision 296181) +++ head/sys/boot/uboot/lib/elf_freebsd.c (revision 296182) @@ -1,96 +1,100 @@ /*- * Copyright (c) 2001 Benno Rice * Copyright (c) 2007 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 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 +#ifdef __mips__ +#include +#include +#endif #include #include #include #include #include "bootstrap.h" #include "libuboot.h" extern vm_offset_t md_load(char *, vm_offset_t *); int __elfN(uboot_load)(char *filename, u_int64_t dest, struct preloaded_file **result) { int r; r = __elfN(loadfile)(filename, dest, result); if (r != 0) return (r); #if defined(__powerpc__) /* * No need to sync the icache for modules: this will * be done by the kernel after relocation. */ if (!strcmp((*result)->f_type, "elf kernel")) __syncicache((void *) (*result)->f_addr, (*result)->f_size); #endif return (0); } int __elfN(uboot_exec)(struct preloaded_file *fp) { struct file_metadata *fmp; vm_offset_t mdp; Elf_Ehdr *e; int error; void (*entry)(void *); if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) return (EFTYPE); e = (Elf_Ehdr *)&fmp->md_data; if ((error = md_load(fp->f_args, &mdp)) != 0) return (error); entry = (void *)e->e_entry; - printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel entry at 0x%p...\n", entry); dev_cleanup(); printf("Kernel args: %s\n", fp->f_args); (*entry)((void *)mdp); panic("exec returned"); } struct file_format uboot_elf = { __elfN(uboot_load), __elfN(uboot_exec) }; Index: head/sys/boot/uboot/lib/glue.c =================================================================== --- head/sys/boot/uboot/lib/glue.c (revision 296181) +++ head/sys/boot/uboot/lib/glue.c (revision 296182) @@ -1,528 +1,529 @@ /*- * 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 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 "api_public.h" #include "glue.h" #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif /* Some random address used by U-Boot. */ extern long uboot_address; static int valid_sig(struct api_signature *sig) { uint32_t checksum; struct api_signature s; if (sig == NULL) return (0); /* * Clear the checksum field (in the local copy) so as to calculate the * CRC with the same initial contents as at the time when the sig was * produced */ s = *sig; s.checksum = 0; checksum = crc32((void *)&s, sizeof(struct api_signature)); if (checksum != sig->checksum) return (0); return (1); } /* * Searches for the U-Boot API signature * * returns 1/0 depending on found/not found result */ int api_search_sig(struct api_signature **sig) { unsigned char *sp, *spend; if (sig == NULL) return (0); if (uboot_address == 0) uboot_address = 255 * 1024 * 1024; - sp = (void *)(uboot_address & ~0x000fffff); - spend = sp + 0x00300000 - API_SIG_MAGLEN; + sp = (void *)(uboot_address & API_SIG_SEARCH_MASK); + spend = sp + API_SIG_SEARCH_LEN - API_SIG_MAGLEN; + while (sp < spend) { if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) { *sig = (struct api_signature *)sp; if (valid_sig(*sig)) return (1); } sp += API_SIG_MAGLEN; } *sig = NULL; return (0); } /**************************************** * * console * ****************************************/ int ub_getc(void) { int c; - if (!syscall(API_GETC, NULL, (uint32_t)&c)) + if (!syscall(API_GETC, NULL, &c)) return (-1); return (c); } int ub_tstc(void) { int t; - if (!syscall(API_TSTC, NULL, (uint32_t)&t)) + if (!syscall(API_TSTC, NULL, &t)) return (-1); return (t); } void -ub_putc(char c) +ub_putc(const char c) { - syscall(API_PUTC, NULL, (uint32_t)&c); + syscall(API_PUTC, NULL, &c); } void ub_puts(const char *s) { - syscall(API_PUTS, NULL, (uint32_t)s); + syscall(API_PUTS, NULL, s); } /**************************************** * * system * ****************************************/ void ub_reset(void) { syscall(API_RESET, NULL); } static struct mem_region mr[UB_MAX_MR]; static struct sys_info si; struct sys_info * ub_get_sys_info(void) { int err = 0; memset(&si, 0, sizeof(struct sys_info)); si.mr = mr; si.mr_no = UB_MAX_MR; memset(&mr, 0, sizeof(mr)); - if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si)) + if (!syscall(API_GET_SYS_INFO, &err, &si)) return (NULL); return ((err) ? NULL : &si); } /**************************************** * * timing * ****************************************/ void ub_udelay(unsigned long usec) { syscall(API_UDELAY, NULL, &usec); } unsigned long ub_get_timer(unsigned long base) { unsigned long cur; if (!syscall(API_GET_TIMER, NULL, &cur, &base)) return (0); return (cur); } /**************************************************************************** * * devices * * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1 * ***************************************************************************/ static struct device_info devices[UB_MAX_DEV]; struct device_info * ub_dev_get(int i) { return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]); } /* * Enumerates the devices: fills out device_info elements in the devices[] * array. * * returns: number of devices found */ int ub_dev_enum(void) { struct device_info *di; int n = 0; memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV); di = &devices[0]; if (!syscall(API_DEV_ENUM, NULL, di)) return (0); while (di->cookie != NULL) { if (++n >= UB_MAX_DEV) break; /* take another device_info */ di++; /* pass on the previous cookie */ di->cookie = devices[n - 1].cookie; if (!syscall(API_DEV_ENUM, NULL, di)) return (0); } return (n); } /* * handle: 0-based id of the device * * returns: 0 when OK, err otherwise */ int ub_dev_open(int handle) { struct device_info *di; int err = 0; if (handle < 0 || handle >= UB_MAX_DEV) return (API_EINVAL); di = &devices[handle]; if (!syscall(API_DEV_OPEN, &err, di)) return (-1); return (err); } int ub_dev_close(int handle) { struct device_info *di; if (handle < 0 || handle >= UB_MAX_DEV) return (API_EINVAL); di = &devices[handle]; if (!syscall(API_DEV_CLOSE, NULL, di)) return (-1); return (0); } /* * Validates device for read/write, it has to: * * - have sane handle * - be opened * * returns: 0/1 accordingly */ static int dev_valid(int handle) { if (handle < 0 || handle >= UB_MAX_DEV) return (0); if (devices[handle].state != DEV_STA_OPEN) return (0); return (1); } static int dev_stor_valid(int handle) { if (!dev_valid(handle)) return (0); if (!(devices[handle].type & DEV_TYP_STOR)) return (0); return (1); } int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start, lbasize_t *rlen) { struct device_info *di; lbasize_t act_len; int err = 0; if (!dev_stor_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len)) return (API_ESYSC); if (!err && rlen) *rlen = act_len; return (err); } static int dev_net_valid(int handle) { if (!dev_valid(handle)) return (0); if (devices[handle].type != DEV_TYP_NET) return (0); return (1); } int ub_dev_recv(int handle, void *buf, int len, int *rlen) { struct device_info *di; int err = 0, act_len; if (!dev_net_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len)) return (API_ESYSC); if (!err) *rlen = act_len; return (err); } int ub_dev_send(int handle, void *buf, int len) { struct device_info *di; int err = 0; if (!dev_net_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_WRITE, &err, di, buf, &len)) return (API_ESYSC); return (err); } char * ub_stor_type(int type) { if (type & DT_STOR_IDE) return ("IDE"); if (type & DT_STOR_SCSI) return ("SCSI"); if (type & DT_STOR_USB) return ("USB"); if (type & DT_STOR_MMC) return ("MMC"); if (type & DT_STOR_SATA) return ("SATA"); return ("Unknown"); } char * ub_mem_type(int flags) { switch (flags & 0x000F) { case MR_ATTR_FLASH: return ("FLASH"); case MR_ATTR_DRAM: return ("DRAM"); case MR_ATTR_SRAM: return ("SRAM"); default: return ("Unknown"); } } void ub_dump_di(int handle) { struct device_info *di = ub_dev_get(handle); int i; printf("device info (%d):\n", handle); - printf(" cookie\t= 0x%08x\n", (uint32_t)di->cookie); + printf(" cookie\t= 0x%p\n", di->cookie); printf(" type\t\t= 0x%08x\n", di->type); if (di->type == DEV_TYP_NET) { printf(" hwaddr\t= "); for (i = 0; i < 6; i++) printf("%02x ", di->di_net.hwaddr[i]); printf("\n"); } else if (di->type & DEV_TYP_STOR) { printf(" type\t\t= %s\n", ub_stor_type(di->type)); printf(" blk size\t\t= %ld\n", di->di_stor.block_size); printf(" blk count\t\t= %ld\n", di->di_stor.block_count); } } void ub_dump_si(struct sys_info *si) { int i; printf("sys info:\n"); printf(" clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000); printf(" clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000); printf(" bar\t\t= 0x%08lx\n", si->bar); printf("---\n"); for (i = 0; i < si->mr_no; i++) { if (si->mr[i].flags == 0) break; printf(" start\t= 0x%08lx\n", si->mr[i].start); printf(" size\t= 0x%08lx\n", si->mr[i].size); printf(" type\t= %s\n", ub_mem_type(si->mr[i].flags)); printf("---\n"); } } /**************************************** * * env vars * ****************************************/ char * ub_env_get(const char *name) { char *value; - if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value)) + if (!syscall(API_ENV_GET, NULL, name, &value)) return (NULL); return (value); } void ub_env_set(const char *name, char *value) { - syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value); + syscall(API_ENV_SET, NULL, name, value); } static char env_name[256]; const char * ub_env_enum(const char *last) { const char *env, *str; int i; /* * It's OK to pass only the name piece as last (and not the whole * 'name=val' string), since the API_ENUM_ENV call uses envmatch() * internally, which handles such case */ env = NULL; - if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env)) + if (!syscall(API_ENV_ENUM, NULL, last, &env)) return (NULL); if (env == NULL || last == env) /* no more env. variables to enumerate */ return (NULL); /* next enumerated env var */ memset(env_name, 0, 256); for (i = 0, str = env; *str != '=' && *str != '\0';) env_name[i++] = *str++; env_name[i] = '\0'; return (env_name); } Index: head/sys/boot/uboot/lib/glue.h =================================================================== --- head/sys/boot/uboot/lib/glue.h (revision 296181) +++ head/sys/boot/uboot/lib/glue.h (revision 296182) @@ -1,86 +1,106 @@ /*- * Copyright (c) 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 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$ */ /* * This is the header file for conveniency wrapper routines (API glue) */ #ifndef _API_GLUE_H_ #define _API_GLUE_H_ #include "api_public.h" +/* + * Mask used to align the start address for API signature search to 1MiB + */ +#define API_SIG_SEARCH_MASK ~0x000fffff + +#ifdef __mips__ +/* + * On MIPS, U-Boot passes us a hint address, which is very close to the end of + * RAM (less than 1MiB), so searching for the API signature within more than + * that leads to exception. + */ +#define API_SIG_SEARCH_LEN 0x00100000 +#else +/* + * Search for the API signature within 3MiB of the 1MiB-aligned address that + * U-Boot has hinted us. + */ +#define API_SIG_SEARCH_LEN 0x00300000 +#endif + int syscall(int, int *, ...); void *syscall_ptr; int api_search_sig(struct api_signature **sig); #define UB_MAX_MR 16 /* max mem regions number */ #define UB_MAX_DEV 6 /* max devices number */ /* * The ub_ library calls are part of the application, not U-Boot code! They * are front-end wrappers that are used by the consumer application: they * prepare arguments for particular syscall and jump to the low level * syscall() */ /* console */ int ub_getc(void); int ub_tstc(void); void ub_putc(char); void ub_puts(const char *); /* system */ void ub_reset(void); struct sys_info *ub_get_sys_info(void); /* time */ void ub_udelay(unsigned long); unsigned long ub_get_timer(unsigned long); /* env vars */ char *ub_env_get(const char *); void ub_env_set(const char *, char *); const char *ub_env_enum(const char *); /* devices */ int ub_dev_enum(void); int ub_dev_open(int); int ub_dev_close(int); int ub_dev_read(int, void *, lbasize_t, lbastart_t, lbasize_t *); int ub_dev_send(int, void *, int); int ub_dev_recv(int, void *, int, int *); struct device_info *ub_dev_get(int); void ub_dump_di(int); void ub_dump_si(struct sys_info *); char *ub_mem_type(int); char *ub_stor_type(int); #endif /* _API_GLUE_H_ */