Index: stable/11/sys/boot/common/bcache.c =================================================================== --- stable/11/sys/boot/common/bcache.c (revision 329009) +++ stable/11/sys/boot/common/bcache.c (revision 329010) @@ -1,454 +1,456 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright 2015 Toomas Soome * 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 #include __FBSDID("$FreeBSD$"); /* * Simple hashed block cache */ #include #include #include #include #include "bootstrap.h" /* #define BCACHE_DEBUG */ #ifdef BCACHE_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif struct bcachectl { daddr_t bc_blkno; int bc_count; }; /* * bcache per device node. cache is allocated on device first open and freed * on last close, to save memory. The issue there is the size; biosdisk * supports up to 31 (0x1f) devices. Classic setup would use single disk * to boot from, but this has changed with zfs. */ struct bcache { struct bcachectl *bcache_ctl; caddr_t bcache_data; u_int bcache_nblks; size_t ra; }; static u_int bcache_total_nblks; /* set by bcache_init */ static u_int bcache_blksize; /* set by bcache_init */ static u_int bcache_numdev; /* set by bcache_add_dev */ /* statistics */ static u_int bcache_units; /* number of devices with cache */ static u_int bcache_unit_nblks; /* nblocks per unit */ static u_int bcache_hits; static u_int bcache_misses; static u_int bcache_ops; static u_int bcache_bypasses; static u_int bcache_bcount; static u_int bcache_rablks; #define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1)) #define BCACHE_LOOKUP(bc, blkno) \ ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) #define BCACHE_READAHEAD 256 #define BCACHE_MINREADAHEAD 32 static void bcache_invalidate(struct bcache *bc, daddr_t blkno); static void bcache_insert(struct bcache *bc, daddr_t blkno); static void bcache_free_instance(struct bcache *bc); /* * Initialise the cache for (nblks) of (bsize). */ void bcache_init(u_int nblks, size_t bsize) { /* set up control data */ bcache_total_nblks = nblks; bcache_blksize = bsize; } /* * add number of devices to bcache. we have to divide cache space * between the devices, so bcache_add_dev() can be used to set up the * number. The issue is, we need to get the number before actual allocations. * bcache_add_dev() is supposed to be called from device init() call, so the * assumption is, devsw dv_init is called for plain devices first, and * for zfs, last. */ void bcache_add_dev(int devices) { bcache_numdev += devices; } void * bcache_allocate(void) { u_int i; struct bcache *bc = malloc(sizeof (struct bcache)); int disks = bcache_numdev; if (disks == 0) disks = 1; /* safe guard */ if (bc == NULL) { errno = ENOMEM; return (bc); } /* * the bcache block count must be power of 2 for hash function */ i = fls(disks) - 1; /* highbit - 1 */ if (disks > (1 << i)) /* next power of 2 */ i++; bc->bcache_nblks = bcache_total_nblks >> i; bcache_unit_nblks = bc->bcache_nblks; bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); if (bc->bcache_data == NULL) { /* dont error out yet. fall back to 32 blocks and try again */ bc->bcache_nblks = 32; bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); } bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof(struct bcachectl)); if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { bcache_free_instance(bc); errno = ENOMEM; return(NULL); } /* Flush the cache */ for (i = 0; i < bc->bcache_nblks; i++) { bc->bcache_ctl[i].bc_count = -1; bc->bcache_ctl[i].bc_blkno = -1; } bcache_units++; bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */ return (bc); } void bcache_free(void *cache) { struct bcache *bc = cache; if (bc == NULL) return; bcache_free_instance(bc); bcache_units--; } /* * Handle a write request; write directly to the disk, and populate the * cache with the new values. */ static int write_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; struct bcache *bc = dd->dv_cache; daddr_t i, nblk; nblk = size / bcache_blksize; /* Invalidate the blocks being written */ for (i = 0; i < nblk; i++) { bcache_invalidate(bc, blk + i); } /* Write the blocks */ return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); } /* * Handle a read request; fill in parts of the request that can * be satisfied by the cache, use the supplied strategy routine to do * device I/O and then use the I/O results to populate the cache. */ static int read_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; struct bcache *bc = dd->dv_cache; size_t i, nblk, p_size, r_size, complete, ra; int result; daddr_t p_blk; caddr_t p_buf; if (bc == NULL) { errno = ENODEV; return (-1); } if (rsize != NULL) *rsize = 0; nblk = size / bcache_blksize; if (nblk == 0 && size != 0) nblk++; result = 0; complete = 1; /* Satisfy any cache hits up front, break on first miss */ for (i = 0; i < nblk; i++) { if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) { bcache_misses += (nblk - i); complete = 0; if (nblk - i > BCACHE_MINREADAHEAD && bc->ra > BCACHE_MINREADAHEAD) bc->ra >>= 1; /* reduce read ahead */ break; } else { bcache_hits++; } } if (complete) { /* whole set was in cache, return it */ if (bc->ra < BCACHE_READAHEAD) bc->ra <<= 1; /* increase read ahead */ bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), buf, size); goto done; } /* * Fill in any misses. From check we have i pointing to first missing * block, read in all remaining blocks + readahead. * We have space at least for nblk - i before bcache wraps. */ p_blk = blk + i; p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk)); r_size = bc->bcache_nblks - BHASH(bc, p_blk); /* remaining blocks */ p_size = MIN(r_size, nblk - i); /* read at least those blocks */ ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); if (ra != bc->bcache_nblks) { /* do we have RA space? */ ra = MIN(bc->ra, ra); p_size += ra; } /* invalidate bcache */ for (i = 0; i < p_size; i++) { bcache_invalidate(bc, p_blk + i); } r_size = 0; /* * with read-ahead, it may happen we are attempting to read past * disk end, as bcache has no information about disk size. * in such case we should get partial read if some blocks can be * read or error, if no blocks can be read. * in either case we should return the data in bcache and only * return error if there is no data. */ result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, &r_size); r_size /= bcache_blksize; for (i = 0; i < r_size; i++) bcache_insert(bc, p_blk + i); /* update ra statistics */ if (r_size != 0) { if (r_size < p_size) bcache_rablks += (p_size - r_size); else bcache_rablks += ra; } /* check how much data can we copy */ for (i = 0; i < nblk; i++) { if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) break; } - size = i * bcache_blksize; + if (size > i * bcache_blksize) + size = i * bcache_blksize; + if (size != 0) { bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), buf, size); result = 0; } done: if ((result == 0) && (rsize != NULL)) *rsize = size; return(result); } /* * Requests larger than 1/2 cache size will be bypassed and go * directly to the disk. XXX tune this. */ int bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; struct bcache *bc = dd->dv_cache; u_int bcache_nblks = 0; int nblk, cblk, ret; size_t csize, isize, total; bcache_ops++; if (bc != NULL) bcache_nblks = bc->bcache_nblks; /* bypass large requests, or when the cache is inactive */ if (bc == NULL || ((size * 2 / bcache_blksize) > bcache_nblks)) { DEBUG("bypass %d from %d", size / bcache_blksize, blk); bcache_bypasses++; return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); } switch (rw) { case F_READ: nblk = size / bcache_blksize; if (size != 0 && nblk == 0) nblk++; /* read at least one block */ ret = 0; total = 0; while(size) { cblk = bcache_nblks - BHASH(bc, blk); /* # of blocks left */ cblk = MIN(cblk, nblk); if (size <= bcache_blksize) csize = size; else csize = cblk * bcache_blksize; ret = read_strategy(devdata, rw, blk, csize, buf+total, &isize); /* * we may have error from read ahead, if we have read some data * return partial read. */ if (ret != 0 || isize == 0) { if (total != 0) ret = 0; break; } blk += isize / bcache_blksize; total += isize; size -= isize; nblk = size / bcache_blksize; } if (rsize) *rsize = total; return (ret); case F_WRITE: return write_strategy(devdata, rw, blk, size, buf, rsize); } return -1; } /* * Free allocated bcache instance */ static void bcache_free_instance(struct bcache *bc) { if (bc != NULL) { if (bc->bcache_ctl) free(bc->bcache_ctl); if (bc->bcache_data) free(bc->bcache_data); free(bc); } } /* * Insert a block into the cache. */ static void bcache_insert(struct bcache *bc, daddr_t blkno) { u_int cand; cand = BHASH(bc, blkno); DEBUG("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount); bc->bcache_ctl[cand].bc_blkno = blkno; bc->bcache_ctl[cand].bc_count = bcache_bcount++; } /* * Invalidate a block from the cache. */ static void bcache_invalidate(struct bcache *bc, daddr_t blkno) { u_int i; i = BHASH(bc, blkno); if (bc->bcache_ctl[i].bc_blkno == blkno) { bc->bcache_ctl[i].bc_count = -1; bc->bcache_ctl[i].bc_blkno = -1; DEBUG("invalidate blk %llu", blkno); } } #ifndef BOOT2 COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache); static int command_bcache(int argc, char *argv[]) { if (argc != 1) { command_errmsg = "wrong number of arguments"; return(CMD_ERROR); } printf("\ncache blocks: %d\n", bcache_total_nblks); printf("cache blocksz: %d\n", bcache_blksize); printf("cache readahead: %d\n", bcache_rablks); printf("unit cache blocks: %d\n", bcache_unit_nblks); printf("cached units: %d\n", bcache_units); printf("%d ops %d bypasses %d hits %d misses\n", bcache_ops, bcache_bypasses, bcache_hits, bcache_misses); return(CMD_OK); } #endif Index: stable/11/sys/boot/common/boot.c =================================================================== --- stable/11/sys/boot/common/boot.c (revision 329009) +++ stable/11/sys/boot/common/boot.c (revision 329010) @@ -1,408 +1,410 @@ /*- * 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$"); /* * Loading modules, booting the system */ #include #include #include "bootstrap.h" static char *getbootfile(int try); static int loadakernel(int try, int argc, char* argv[]); /* List of kernel names to try (may be overwritten by boot.config) XXX should move from here? */ static const char *default_bootfiles = "kernel"; static int autoboot_tried; /* * The user wants us to boot. */ COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); static int command_boot(int argc, char *argv[]) { struct preloaded_file *fp; /* * See if the user has specified an explicit kernel to boot. */ if ((argc > 1) && (argv[1][0] != '-')) { /* XXX maybe we should discard everything and start again? */ if (file_findfile(NULL, NULL) != NULL) { - sprintf(command_errbuf, "can't boot '%s', kernel module already loaded", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't boot '%s', kernel module already loaded", argv[1]); return(CMD_ERROR); } /* find/load the kernel module */ if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) return(CMD_ERROR); /* we have consumed all arguments */ argc = 1; } /* * See if there is a kernel module already loaded */ if (file_findfile(NULL, NULL) == NULL) if (loadakernel(0, argc - 1, argv + 1)) /* we have consumed all arguments */ argc = 1; /* * Loaded anything yet? */ if ((fp = file_findfile(NULL, NULL)) == NULL) { command_errmsg = "no bootable kernel"; return(CMD_ERROR); } /* * If we were given arguments, discard any previous. * XXX should we merge arguments? Hard to DWIM. */ if (argc > 1) { if (fp->f_args != NULL) free(fp->f_args); fp->f_args = unargv(argc - 1, argv + 1); } /* Hook for platform-specific autoloading of modules */ if (archsw.arch_autoload() != 0) return(CMD_ERROR); /* Call the exec handler from the loader matching the kernel */ file_formats[fp->f_loader]->l_exec(fp); return(CMD_ERROR); } /* * Autoboot after a delay */ COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", command_autoboot); static int command_autoboot(int argc, char *argv[]) { int howlong; char *cp, *prompt; prompt = NULL; howlong = -1; switch(argc) { case 3: prompt = argv[2]; /* FALLTHROUGH */ case 2: howlong = strtol(argv[1], &cp, 0); if (*cp != 0) { - sprintf(command_errbuf, "bad delay '%s'", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "bad delay '%s'", argv[1]); return(CMD_ERROR); } /* FALLTHROUGH */ case 1: return(autoboot(howlong, prompt)); } command_errmsg = "too many arguments"; return(CMD_ERROR); } /* * Called before we go interactive. If we think we can autoboot, and * we haven't tried already, try now. */ void autoboot_maybe() { char *cp; cp = getenv("autoboot_delay"); if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) autoboot(-1, NULL); /* try to boot automatically */ } int autoboot(int timeout, char *prompt) { time_t when, otime, ntime; int c, yes; char *argv[2], *cp, *ep; char *kernelname; #ifdef BOOT_PROMPT_123 const char *seq = "123", *p = seq; #endif autoboot_tried = 1; if (timeout == -1) { timeout = 10; /* try to get a delay from the environment */ if ((cp = getenv("autoboot_delay"))) { timeout = strtol(cp, &ep, 0); if (cp == ep) timeout = 10; /* Unparseable? Set default! */ } } kernelname = getenv("kernelname"); if (kernelname == NULL) { argv[0] = NULL; loadakernel(0, 0, argv); kernelname = getenv("kernelname"); if (kernelname == NULL) { command_errmsg = "no valid kernel found"; return(CMD_ERROR); } } if (timeout >= 0) { otime = time(NULL); when = otime + timeout; /* when to boot */ yes = 0; #ifdef BOOT_PROMPT_123 printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or " "1 2 3 sequence for command prompt." : prompt); #else printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt); #endif for (;;) { if (ischar()) { c = getchar(); #ifdef BOOT_PROMPT_123 if ((c == '\r') || (c == '\n')) { yes = 1; break; } else if (c != *p++) p = seq; if (*p == 0) break; #else if ((c == '\r') || (c == '\n')) yes = 1; break; #endif } ntime = time(NULL); if (ntime >= when) { yes = 1; break; } if (ntime != otime) { printf("\rBooting [%s] in %d second%s... ", kernelname, (int)(when - ntime), (when-ntime)==1?"":"s"); otime = ntime; } } } else { yes = 1; } if (yes) printf("\rBooting [%s]... ", kernelname); putchar('\n'); if (yes) { argv[0] = "boot"; argv[1] = NULL; return(command_boot(1, argv)); } return(CMD_OK); } /* * Scrounge for the name of the (try)'th file we will try to boot. */ static char * getbootfile(int try) { static char *name = NULL; const char *spec, *ep; size_t len; /* we use dynamic storage */ if (name != NULL) { free(name); name = NULL; } /* * Try $bootfile, then try our builtin default */ if ((spec = getenv("bootfile")) == NULL) spec = default_bootfiles; while ((try > 0) && (spec != NULL)) { spec = strchr(spec, ';'); if (spec) spec++; /* skip over the leading ';' */ try--; } if (spec != NULL) { if ((ep = strchr(spec, ';')) != NULL) { len = ep - spec; } else { len = strlen(spec); } name = malloc(len + 1); strncpy(name, spec, len); name[len] = 0; } if (name && name[0] == 0) { free(name); name = NULL; } return(name); } /* * Try to find the /etc/fstab file on the filesystem (rootdev), * which should be be the root filesystem, and parse it to find * out what the kernel ought to think the root filesystem is. * * If we're successful, set vfs.root.mountfrom to : * so that the kernel can tell both which VFS and which node to use * to mount the device. If this variable's already set, don't * overwrite it. */ int getrootmount(char *rootdev) { char lbuf[128], *cp, *ep, *dev, *fstyp, *options; int fd, error; if (getenv("vfs.root.mountfrom") != NULL) return(0); error = 1; sprintf(lbuf, "%s/etc/fstab", rootdev); if ((fd = open(lbuf, O_RDONLY)) < 0) goto notfound; /* loop reading lines from /etc/fstab What was that about sscanf again? */ while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) { if ((lbuf[0] == 0) || (lbuf[0] == '#')) continue; /* skip device name */ for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) ; if (*cp == 0) /* misformatted */ continue; /* delimit and save */ *cp++ = 0; dev = strdup(lbuf); /* skip whitespace up to mountpoint */ while ((*cp != 0) && isspace(*cp)) cp++; /* must have / to be root */ if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) continue; /* skip whitespace up to fstype */ cp += 2; while ((*cp != 0) && isspace(*cp)) cp++; if (*cp == 0) /* misformatted */ continue; /* skip text to end of fstype and delimit */ ep = cp; while ((*cp != 0) && !isspace(*cp)) cp++; *cp = 0; fstyp = strdup(ep); /* skip whitespace up to mount options */ cp += 1; while ((*cp != 0) && isspace(*cp)) cp++; if (*cp == 0) /* misformatted */ continue; /* skip text to end of mount options and delimit */ ep = cp; while ((*cp != 0) && !isspace(*cp)) cp++; *cp = 0; options = strdup(ep); /* Build the : and save it in vfs.root.mountfrom */ sprintf(lbuf, "%s:%s", fstyp, dev); free(dev); free(fstyp); setenv("vfs.root.mountfrom", lbuf, 0); /* Don't override vfs.root.mountfrom.options if it is already set */ if (getenv("vfs.root.mountfrom.options") == NULL) { /* save mount options */ setenv("vfs.root.mountfrom.options", options, 0); } free(options); error = 0; break; } close(fd); notfound: if (error) { const char *currdev; currdev = getenv("currdev"); if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { cp = strdup(currdev); cp[strlen(cp) - 1] = '\0'; setenv("vfs.root.mountfrom", cp, 0); error = 0; } } return(error); } static int loadakernel(int try, int argc, char* argv[]) { char *cp; for (try = 0; (cp = getbootfile(try)) != NULL; try++) if (mod_loadkld(cp, argc - 1, argv + 1) != 0) printf("can't load '%s'\n", cp); else return 1; return 0; } Index: stable/11/sys/boot/common/bootstrap.h =================================================================== --- stable/11/sys/boot/common/bootstrap.h (revision 329009) +++ stable/11/sys/boot/common/bootstrap.h (revision 329010) @@ -1,335 +1,336 @@ /*- * 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 char *command_errmsg; -extern char command_errbuf[]; /* XXX blah, length */ +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(const char *rc); int include(const char *filename); /* interp_backslash.c */ char *backslash(char *str); /* interp_parse.c */ int parse(int *argc, char ***argv, char *str); /* interp_forth.c */ void bf_init(const char *rc); int bf_run(char *line); /* boot.c */ int autoboot(int timeout, char *prompt); void autoboot_maybe(void); int getrootmount(char *rootdev); /* 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(u_int 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 pnpinfo_stql pnp_devices; 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(u_int8_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; /* * 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; u_int16_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, u_int64_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 u_int64_t __elfN(relocation_offset); struct elf_file; typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx); int __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result); int __elfN(obj_loadfile)(char *filename, u_int64_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, u_int64_t dest, struct preloaded_file **result, int multiboot); int __elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_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); }; 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 /* Allow lint to override */ #define CTASSERT(x) _CTASSERT(x, __LINE__) #define _CTASSERT(x, y) __CTASSERT(x, y) #define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] #endif #endif /* !_BOOTSTRAP_H_ */ Index: stable/11/sys/boot/common/commands.c =================================================================== --- stable/11/sys/boot/common/commands.c (revision 329009) +++ stable/11/sys/boot/common/commands.c (revision 329010) @@ -1,505 +1,511 @@ /*- * 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$"); #include #include #include "bootstrap.h" char *command_errmsg; -char command_errbuf[256]; /* XXX should have procedural interface for setting, size limit? */ +/* XXX should have procedural interface for setting, size limit? */ +char command_errbuf[COMMAND_ERRBUFSZ]; static int page_file(char *filename); /* * Help is read from a formatted text file. * * Entries in the file are formatted as # Ttopic [Ssubtopic] Ddescription help text here # * * Note that for code simplicity's sake, the above format must be followed * exactly. * * Subtopic entries must immediately follow the topic (this is used to * produce the listing of subtopics). * * If no argument(s) are supplied by the user, the help for 'help' is displayed. */ COMMAND_SET(help, "help", "detailed help", command_help); static int help_getnext(int fd, char **topic, char **subtopic, char **desc) { char line[81], *cp, *ep; for (;;) { if (fgetstr(line, 80, fd) < 0) return(0); if ((strlen(line) < 3) || (line[0] != '#') || (line[1] != ' ')) continue; *topic = *subtopic = *desc = NULL; cp = line + 2; while((cp != NULL) && (*cp != 0)) { ep = strchr(cp, ' '); if ((*cp == 'T') && (*topic == NULL)) { if (ep != NULL) *ep++ = 0; *topic = strdup(cp + 1); } else if ((*cp == 'S') && (*subtopic == NULL)) { if (ep != NULL) *ep++ = 0; *subtopic = strdup(cp + 1); } else if (*cp == 'D') { *desc = strdup(cp + 1); ep = NULL; } cp = ep; } if (*topic == NULL) { if (*subtopic != NULL) free(*subtopic); if (*desc != NULL) free(*desc); continue; } return(1); } } static int help_emitsummary(char *topic, char *subtopic, char *desc) { int i; pager_output(" "); pager_output(topic); i = strlen(topic); if (subtopic != NULL) { pager_output(" "); pager_output(subtopic); i += strlen(subtopic) + 1; } if (desc != NULL) { do { pager_output(" "); } while (i++ < 30); pager_output(desc); } return (pager_output("\n")); } static int command_help(int argc, char *argv[]) { char buf[81]; /* XXX buffer size? */ int hfd, matched, doindex; char *topic, *subtopic, *t, *s, *d; /* page the help text from our load path */ sprintf(buf, "%s/boot/loader.help", getenv("loaddev")); if ((hfd = open(buf, O_RDONLY)) < 0) { printf("Verbose help not available, use '?' to list commands\n"); return(CMD_OK); } /* pick up request from arguments */ topic = subtopic = NULL; switch(argc) { case 3: subtopic = strdup(argv[2]); case 2: topic = strdup(argv[1]); break; case 1: topic = strdup("help"); break; default: command_errmsg = "usage is 'help []"; close(hfd); return(CMD_ERROR); } /* magic "index" keyword */ doindex = !strcmp(topic, "index"); matched = doindex; /* Scan the helpfile looking for help matching the request */ pager_open(); while(help_getnext(hfd, &t, &s, &d)) { if (doindex) { /* dink around formatting */ if (help_emitsummary(t, s, d)) break; } else if (strcmp(topic, t)) { /* topic mismatch */ if(matched) /* nothing more on this topic, stop scanning */ break; } else { /* topic matched */ matched = 1; if (((subtopic == NULL) && (s == NULL)) || ((subtopic != NULL) && (s != NULL) && !strcmp(subtopic, s))) { /* exact match, print text */ while((fgetstr(buf, 80, hfd) >= 0) && (buf[0] != '#')) { if (pager_output(buf)) break; if (pager_output("\n")) break; } } else if ((subtopic == NULL) && (s != NULL)) { /* topic match, list subtopics */ if (help_emitsummary(t, s, d)) break; } } free(t); free(s); free(d); } pager_close(); close(hfd); if (!matched) { - sprintf(command_errbuf, "no help available for '%s'", topic); + snprintf(command_errbuf, sizeof(command_errbuf), + "no help available for '%s'", topic); free(topic); if (subtopic) free(subtopic); return(CMD_ERROR); } free(topic); if (subtopic) free(subtopic); return(CMD_OK); } COMMAND_SET(commandlist, "?", "list commands", command_commandlist); /* * Please note: although we use the pager for the list of commands, * this routine is called from the ? FORTH function which then * unconditionally prints some commands. This will lead to anomalous * behavior. There's no 'pager_output' binding to FORTH to allow * things to work right, so I'm documenting the bug rather than * fixing it. */ static int command_commandlist(int argc, char *argv[]) { struct bootblk_command **cmdp; int res; char name[20]; res = 0; pager_open(); res = pager_output("Available commands:\n"); SET_FOREACH(cmdp, Xcommand_set) { if (res) break; if (((*cmdp)->c_name != NULL) && ((*cmdp)->c_desc != NULL)) { sprintf(name, " %-15s ", (*cmdp)->c_name); pager_output(name); pager_output((*cmdp)->c_desc); res = pager_output("\n"); } } pager_close(); return(CMD_OK); } /* * XXX set/show should become set/echo if we have variable * substitution happening. */ COMMAND_SET(show, "show", "show variable(s)", command_show); static int command_show(int argc, char *argv[]) { struct env_var *ev; char *cp; if (argc < 2) { /* * With no arguments, print everything. */ pager_open(); for (ev = environ; ev != NULL; ev = ev->ev_next) { pager_output(ev->ev_name); cp = getenv(ev->ev_name); if (cp != NULL) { pager_output("="); pager_output(cp); } if (pager_output("\n")) break; } pager_close(); } else { if ((cp = getenv(argv[1])) != NULL) { printf("%s\n", cp); } else { - sprintf(command_errbuf, "variable '%s' not found", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "variable '%s' not found", argv[1]); return(CMD_ERROR); } } return(CMD_OK); } COMMAND_SET(set, "set", "set a variable", command_set); static int command_set(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "wrong number of arguments"; return(CMD_ERROR); } else { if ((err = putenv(argv[1])) != 0) { command_errmsg = strerror(err); return(CMD_ERROR); } } return(CMD_OK); } COMMAND_SET(unset, "unset", "unset a variable", command_unset); static int command_unset(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "wrong number of arguments"; return(CMD_ERROR); } else { if ((err = unsetenv(argv[1])) != 0) { command_errmsg = strerror(err); return(CMD_ERROR); } } return(CMD_OK); } COMMAND_SET(echo, "echo", "echo arguments", command_echo); static int command_echo(int argc, char *argv[]) { char *s; int nl, ch; nl = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "n")) != -1) { switch(ch) { case 'n': nl = 1; break; case '?': default: /* getopt has already reported an error */ return(CMD_OK); } } argv += (optind); argc -= (optind); s = unargv(argc, argv); if (s != NULL) { printf("%s", s); free(s); } if (!nl) printf("\n"); return(CMD_OK); } /* * A passable emulation of the sh(1) command of the same name. */ COMMAND_SET(read, "read", "read input from the terminal", command_read); static int command_read(int argc, char *argv[]) { char *prompt; int timeout; time_t when; char *cp; char *name; char buf[256]; /* XXX size? */ int c; timeout = -1; prompt = NULL; optind = 1; optreset = 1; while ((c = getopt(argc, argv, "p:t:")) != -1) { switch(c) { case 'p': prompt = optarg; break; case 't': timeout = strtol(optarg, &cp, 0); if (cp == optarg) { - sprintf(command_errbuf, "bad timeout '%s'", optarg); + snprintf(command_errbuf, sizeof(command_errbuf), + "bad timeout '%s'", optarg); return(CMD_ERROR); } break; default: return(CMD_OK); } } argv += (optind); argc -= (optind); name = (argc > 0) ? argv[0]: NULL; if (prompt != NULL) printf("%s", prompt); if (timeout >= 0) { when = time(NULL) + timeout; while (!ischar()) if (time(NULL) >= when) return(CMD_OK); /* is timeout an error? */ } ngets(buf, sizeof(buf)); if (name != NULL) setenv(name, buf, 1); return(CMD_OK); } /* * File pager */ COMMAND_SET(more, "more", "show contents of a file", command_more); static int command_more(int argc, char *argv[]) { int i; int res; char line[80]; res=0; pager_open(); for (i = 1; (i < argc) && (res == 0); i++) { sprintf(line, "*** FILE %s BEGIN ***\n", argv[i]); if (pager_output(line)) break; res = page_file(argv[i]); if (!res) { sprintf(line, "*** FILE %s END ***\n", argv[i]); res = pager_output(line); } } pager_close(); if (res == 0) return CMD_OK; else return CMD_ERROR; } static int page_file(char *filename) { int result; result = pager_file(filename); - if (result == -1) - sprintf(command_errbuf, "error showing %s", filename); + if (result == -1) { + snprintf(command_errbuf, sizeof(command_errbuf), + "error showing %s", filename); + } return result; } /* * List all disk-like devices */ COMMAND_SET(lsdev, "lsdev", "list all devices", command_lsdev); static int command_lsdev(int argc, char *argv[]) { int verbose, ch, i; char line[80]; verbose = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "v")) != -1) { switch(ch) { case 'v': verbose = 1; break; case '?': default: /* getopt has already reported an error */ return(CMD_OK); } } argv += (optind); argc -= (optind); pager_open(); for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_print != NULL){ if (devsw[i]->dv_print(verbose)) break; } else { sprintf(line, "%s: (unknown)\n", devsw[i]->dv_name); if (pager_output(line)) break; } } pager_close(); return(CMD_OK); } Index: stable/11/sys/boot/common/interp.c =================================================================== --- stable/11/sys/boot/common/interp.c (revision 329009) +++ stable/11/sys/boot/common/interp.c (revision 329010) @@ -1,368 +1,372 @@ /*- * 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$"); /* * Simple commandline interpreter, toplevel and misc. * * XXX may be obsoleted by BootFORTH or some other, better, interpreter. */ #include #include #include "bootstrap.h" #ifdef BOOT_FORTH #include "ficl.h" #define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x) extern FICL_VM *bf_vm; #else #define RETURN(x) return(x) #endif #define MAXARGS 20 /* maximum number of arguments allowed */ static void prompt(void); #ifndef BOOT_FORTH static int perform(int argc, char *argv[]); /* * Perform the command */ int perform(int argc, char *argv[]) { int result; struct bootblk_command **cmdp; bootblk_cmd_t *cmd; if (argc < 1) return(CMD_OK); /* set return defaults; a successful command will override these */ command_errmsg = command_errbuf; strcpy(command_errbuf, "no error message"); cmd = NULL; result = CMD_ERROR; /* search the command set for the command */ SET_FOREACH(cmdp, Xcommand_set) { if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name)) cmd = (*cmdp)->c_fn; } if (cmd != NULL) { result = (cmd)(argc, argv); } else { command_errmsg = "unknown command"; } RETURN(result); } #endif /* ! BOOT_FORTH */ /* * Interactive mode */ void interact(const char *rc) { static char input[256]; /* big enough? */ #ifndef BOOT_FORTH int argc; char **argv; #endif #ifdef BOOT_FORTH bf_init((rc) ? "" : NULL); #endif if (rc == NULL) { /* Read our default configuration. */ if (include("/boot/loader.rc") != CMD_OK) include("/boot/boot.conf"); } else if (*rc != '\0') include(rc); printf("\n"); /* * Before interacting, we might want to autoboot. */ autoboot_maybe(); /* * Not autobooting, go manual */ printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); if (getenv("prompt") == NULL) setenv("prompt", "${interpret}", 1); if (getenv("interpret") == NULL) setenv("interpret", "OK", 1); for (;;) { input[0] = '\0'; prompt(); ngets(input, sizeof(input)); #ifdef BOOT_FORTH bf_vm->sourceID.i = 0; bf_run(input); #else if (!parse(&argc, &argv, input)) { if (perform(argc, argv)) printf("%s: %s\n", argv[0], command_errmsg); free(argv); } else { printf("parse error\n"); } #endif } } /* * Read commands from a file, then execute them. * * We store the commands in memory and close the source file so that the media * holding it can safely go away while we are executing. * * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so * that the script won't stop if they fail). */ COMMAND_SET(include, "include", "read commands from a file", command_include); static int command_include(int argc, char *argv[]) { int i; int res; char **argvbuf; /* * Since argv is static, we need to save it here. */ argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); for (i = 0; i < argc; i++) argvbuf[i] = strdup(argv[i]); res=CMD_OK; for (i = 1; (i < argc) && (res == CMD_OK); i++) res = include(argvbuf[i]); for (i = 0; i < argc; i++) free(argvbuf[i]); free(argvbuf); return(res); } /* * Header prepended to each line. The text immediately follows the header. * We try to make this short in order to save memory -- the loader has * limited memory available, and some of the forth files are very long. */ struct includeline { struct includeline *next; #ifndef BOOT_FORTH int flags; int line; #define SL_QUIET (1<<0) #define SL_IGNOREERR (1<<1) #endif char text[0]; }; int include(const char *filename) { struct includeline *script, *se, *sp; char input[256]; /* big enough? */ #ifdef BOOT_FORTH int res; char *cp; int prevsrcid, fd, line; #else int argc,res; char **argv, *cp; int fd, flags, line; #endif if (((fd = open(filename, O_RDONLY)) == -1)) { - sprintf(command_errbuf,"can't open '%s': %s", filename, strerror(errno)); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't open '%s': %s", filename, strerror(errno)); return(CMD_ERROR); } /* * Read the script into memory. */ script = se = NULL; line = 0; while (fgetstr(input, sizeof(input), fd) >= 0) { line++; #ifdef BOOT_FORTH cp = input; #else flags = 0; /* Discard comments */ if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0) continue; cp = input; /* Echo? */ if (input[0] == '@') { cp++; flags |= SL_QUIET; } /* Error OK? */ if (input[0] == '-') { cp++; flags |= SL_IGNOREERR; } #endif /* Allocate script line structure and copy line, flags */ if (*cp == '\0') continue; /* ignore empty line, save memory */ sp = malloc(sizeof(struct includeline) + strlen(cp) + 1); /* On malloc failure (it happens!), free as much as possible and exit */ if (sp == NULL) { while (script != NULL) { se = script; script = script->next; free(se); } - sprintf(command_errbuf, "file '%s' line %d: memory allocation " - "failure - aborting", filename, line); + snprintf(command_errbuf, sizeof(command_errbuf), + "file '%s' line %d: memory allocation failure - aborting", + filename, line); return (CMD_ERROR); } strcpy(sp->text, cp); #ifndef BOOT_FORTH sp->flags = flags; sp->line = line; #endif sp->next = NULL; if (script == NULL) { script = sp; } else { se->next = sp; } se = sp; } close(fd); /* * Execute the script */ #ifndef BOOT_FORTH argv = NULL; #else prevsrcid = bf_vm->sourceID.i; bf_vm->sourceID.i = fd; #endif res = CMD_OK; for (sp = script; sp != NULL; sp = sp->next) { #ifdef BOOT_FORTH res = bf_run(sp->text); if (res != VM_OUTOFTEXT) { - sprintf(command_errbuf, "Error while including %s, in the line:\n%s", filename, sp->text); + snprintf(command_errbuf, sizeof(command_errbuf), + "Error while including %s, in the line:\n%s", + filename, sp->text); res = CMD_ERROR; break; } else res = CMD_OK; #else /* print if not being quiet */ if (!(sp->flags & SL_QUIET)) { prompt(); printf("%s\n", sp->text); } /* Parse the command */ if (!parse(&argc, &argv, sp->text)) { if ((argc > 0) && (perform(argc, argv) != 0)) { /* normal command */ printf("%s: %s\n", argv[0], command_errmsg); if (!(sp->flags & SL_IGNOREERR)) { res=CMD_ERROR; break; } } free(argv); argv = NULL; } else { printf("%s line %d: parse error\n", filename, sp->line); res=CMD_ERROR; break; } #endif } #ifndef BOOT_FORTH if (argv != NULL) free(argv); #else bf_vm->sourceID.i = prevsrcid; #endif while(script != NULL) { se = script; script = script->next; free(se); } return(res); } /* * Emit the current prompt; use the same syntax as the parser * for embedding environment variables. */ static void prompt(void) { char *pr, *p, *cp, *ev; if ((cp = getenv("prompt")) == NULL) cp = ">"; pr = p = strdup(cp); while (*p != 0) { if ((*p == '$') && (*(p+1) == '{')) { for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) ; *cp = 0; ev = getenv(p + 2); if (ev != NULL) printf("%s", ev); p = cp + 1; continue; } putchar(*p++); } putchar(' '); free(pr); } Index: stable/11/sys/boot/common/interp_forth.c =================================================================== --- stable/11/sys/boot/common/interp_forth.c (revision 329009) +++ stable/11/sys/boot/common/interp_forth.c (revision 329010) @@ -1,336 +1,338 @@ /*- * 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$"); #include /* to pick up __FreeBSD_version */ #include #include #include "bootstrap.h" #include "ficl.h" extern unsigned bootprog_rev; /* #define BFORTH_DEBUG */ #ifdef BFORTH_DEBUG #define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else #define DEBUG(fmt, args...) #endif /* * Eventually, all builtin commands throw codes must be defined * elsewhere, possibly bootstrap.h. For now, just this code, used * just in this file, it is getting defined. */ #define BF_PARSE 100 /* * FreeBSD loader default dictionary cells */ #ifndef BF_DICTSIZE #define BF_DICTSIZE 10000 #endif /* * BootForth Interface to Ficl Forth interpreter. */ FICL_SYSTEM *bf_sys; FICL_VM *bf_vm; FICL_WORD *pInterp; /* * Shim for taking commands from BF and passing them out to 'standard' * argv/argc command functions. */ static void bf_command(FICL_VM *vm) { char *name, *line, *tail, *cp; size_t len; struct bootblk_command **cmdp; bootblk_cmd_t *cmd; int nstrings, i; int argc, result; char **argv; /* Get the name of the current word */ name = vm->runningWord->name; /* Find our command structure */ cmd = NULL; SET_FOREACH(cmdp, Xcommand_set) { if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name)) cmd = (*cmdp)->c_fn; } if (cmd == NULL) panic("callout for unknown command '%s'", name); /* Check whether we have been compiled or are being interpreted */ if (stackPopINT(vm->pStack)) { /* * Get parameters from stack, in the format: * an un ... a2 u2 a1 u1 n -- * Where n is the number of strings, a/u are pairs of * address/size for strings, and they will be concatenated * in LIFO order. */ nstrings = stackPopINT(vm->pStack); for (i = 0, len = 0; i < nstrings; i++) len += stackFetch(vm->pStack, i * 2).i + 1; line = malloc(strlen(name) + len + 1); strcpy(line, name); if (nstrings) for (i = 0; i < nstrings; i++) { len = stackPopINT(vm->pStack); cp = stackPopPtr(vm->pStack); strcat(line, " "); strncat(line, cp, len); } } else { /* Get remainder of invocation */ tail = vmGetInBuf(vm); for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++) ; line = malloc(strlen(name) + len + 2); strcpy(line, name); if (len > 0) { strcat(line, " "); strncat(line, tail, len); vmUpdateTib(vm, tail + len); } } DEBUG("cmd '%s'", line); command_errmsg = command_errbuf; command_errbuf[0] = 0; if (!parse(&argc, &argv, line)) { result = (cmd)(argc, argv); free(argv); } else { result=BF_PARSE; } switch (result) { case CMD_CRIT: printf("%s\n", command_errmsg); break; case CMD_FATAL: panic("%s\n", command_errmsg); } free(line); /* * If there was error during nested ficlExec(), we may no longer have * valid environment to return. Throw all exceptions from here. */ if (result != CMD_OK) vmThrow(vm, result); /* This is going to be thrown!!! */ stackPushINT(vm->pStack,result); } /* * Replace a word definition (a builtin command) with another * one that: * * - Throw error results instead of returning them on the stack * - Pass a flag indicating whether the word was compiled or is * being interpreted. * * There is one major problem with builtins that cannot be overcome * in anyway, except by outlawing it. We want builtins to behave * differently depending on whether they have been compiled or they * are being interpreted. Notice that this is *not* the interpreter's * current state. For example: * * : example ls ; immediate * : problem example ; \ "ls" gets executed while compiling * example \ "ls" gets executed while interpreting * * Notice that, though the current state is different in the two * invocations of "example", in both cases "ls" has been * *compiled in*, which is what we really want. * * The problem arises when you tick the builtin. For example: * * : example-1 ['] ls postpone literal ; immediate * : example-2 example-1 execute ; immediate * : problem example-2 ; * example-2 * * We have no way, when we get EXECUTEd, of knowing what our behavior * should be. Thus, our only alternative is to "outlaw" this. See RFI * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related * problem, concerning compile semantics. * * The problem is compounded by the fact that "' builtin CATCH" is valid * and desirable. The only solution is to create an intermediary word. * For example: * * : my-ls ls ; * : example ['] my-ls catch ; * * So, with the below implementation, here is a summary of the behavior * of builtins: * * ls -l \ "interpret" behavior, ie, * \ takes parameters from TIB * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie, * \ takes parameters from the stack * : ex-2 ['] ls catch ; immediate \ undefined behavior * : ex-3 ['] ls catch ; \ undefined behavior * ex-2 ex-3 \ "interpret" behavior, * \ catch works * : ex-4 ex-2 ; \ "compile" behavior, * \ catch does not work * : ex-5 ex-3 ; immediate \ same as ex-2 * : ex-6 ex-3 ; \ same as ex-3 * : ex-7 ['] ex-1 catch ; \ "compile" behavior, * \ catch works * : ex-8 postpone ls ; immediate \ same as ex-2 * : ex-9 postpone ls ; \ same as ex-3 * * As the definition below is particularly tricky, and it's side effects * must be well understood by those playing with it, I'll be heavy on * the comments. * * (if you edit this definition, pay attention to trailing spaces after * each word -- I warned you! :-) ) */ #define BUILTIN_CONSTRUCTOR \ ": builtin: " \ ">in @ " /* save the tib index pointer */ \ "' " /* get next word's xt */ \ "swap >in ! " /* point again to next word */ \ "create " /* create a new definition of the next word */ \ ", " /* save previous definition's xt */ \ "immediate " /* make the new definition an immediate word */ \ \ "does> " /* Now, the *new* definition will: */ \ "state @ if " /* if in compiling state: */ \ "1 postpone literal " /* pass 1 flag to indicate compile */ \ "@ compile, " /* compile in previous definition */ \ "postpone throw " /* throw stack-returned result */ \ "else " /* if in interpreting state: */ \ "0 swap " /* pass 0 flag to indicate interpret */ \ "@ execute " /* call previous definition */ \ "throw " /* throw stack-returned result */ \ "then ; " /* * Initialise the Forth interpreter, create all our commands as words. */ void bf_init(const char *rc) { struct bootblk_command **cmdp; char create_buf[41]; /* 31 characters-long builtins */ int fd; bf_sys = ficlInitSystem(BF_DICTSIZE); bf_vm = ficlNewVM(bf_sys); /* Put all private definitions in a "builtins" vocabulary */ ficlExec(bf_vm, "vocabulary builtins also builtins definitions"); /* Builtin constructor word */ ficlExec(bf_vm, BUILTIN_CONSTRUCTOR); /* make all commands appear as Forth words */ SET_FOREACH(cmdp, Xcommand_set) { ficlBuild(bf_sys, (char *)(*cmdp)->c_name, bf_command, FW_DEFAULT); ficlExec(bf_vm, "forth definitions builtins"); sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); ficlExec(bf_vm, create_buf); ficlExec(bf_vm, "builtins definitions"); } ficlExec(bf_vm, "only forth definitions"); /* Export some version numbers so that code can detect the loader/host version */ ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version); ficlSetEnv(bf_sys, "loader_version", bootprog_rev); pInterp = ficlLookup(bf_sys, "interpret"); /* try to load and run init file if present */ if (rc == NULL) rc = "/boot/boot.4th"; if (*rc != '\0') { fd = open(rc, O_RDONLY); if (fd != -1) { (void)ficlExecFD(bf_vm, fd); close(fd); } } /* Do this again, so that interpret can be redefined. */ pInterp = ficlLookup(bf_sys, "interpret"); } /* * Feed a line of user input to the Forth interpreter */ int bf_run(char *line) { int result; result = ficlExec(bf_vm, line); DEBUG("ficlExec '%s' = %d", line, result); switch (result) { case VM_OUTOFTEXT: case VM_ABORTQ: case VM_QUIT: case VM_ERREXIT: break; case VM_USEREXIT: printf("No where to leave to!\n"); break; case VM_ABORT: printf("Aborted!\n"); break; case BF_PARSE: printf("Parse error!\n"); break; default: - /* Hopefully, all other codes filled this buffer */ - printf("%s\n", command_errmsg); + if (command_errmsg != NULL) { + printf("%s\n", command_errmsg); + command_errmsg = NULL; + } } if (result == VM_USEREXIT) panic("interpreter exit"); setenv("interpret", bf_vm->state ? "" : "OK", 1); - return result; + return (result); } Index: stable/11/sys/boot/common/interp_parse.c =================================================================== --- stable/11/sys/boot/common/interp_parse.c (revision 329009) +++ stable/11/sys/boot/common/interp_parse.c (revision 329010) @@ -1,204 +1,222 @@ /*- * 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. * * Jordan K. Hubbard * 29 August 1998 * * The meat of the simple parser. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bootstrap.h" static void clean(void); static int insert(int *argcp, char *buf); static char *variable_lookup(char *name); #define PARSE_BUFSIZE 1024 /* maximum size of one element */ #define MAXARGS 20 /* maximum number of elements */ static char *args[MAXARGS]; /* * parse: accept a string of input and "parse" it for backslash * substitutions and environment variable expansions (${var}), * returning an argc/argv style vector of whitespace separated * arguments. Returns 0 on success, 1 on failure (ok, ok, so I * wimped-out on the error codes! :). * * Note that the argv array returned must be freed by the caller, but * we own the space allocated for arguments and will free that on next * invocation. This allows argv consumers to modify the array if * required. * * NB: environment variables that expand to more than one whitespace * separated token will be returned as a single argv[] element, not * split in turn. Expanded text is also immune to further backslash * elimination or expansion since this is a one-pass, non-recursive * parser. You didn't specify more than this so if you want more, ask * me. - jkh */ #define PARSE_FAIL(expr) \ if (expr) { \ printf("fail at line %d\n", __LINE__); \ clean(); \ free(copy); \ free(buf); \ return 1; \ } /* Accept the usual delimiters for a variable, returning counterpart */ static char isdelim(int ch) { if (ch == '{') return '}'; else if (ch == '(') return ')'; return '\0'; } static int isquote(int ch) { - return (ch == '\'' || ch == '"'); + return (ch == '\''); } +static int +isdquote(int ch) +{ + return (ch == '"'); +} + int parse(int *argc, char ***argv, char *str) { int ac; char *val, *p, *q, *copy = NULL; size_t i = 0; - char token, tmp, quote, *buf; + char token, tmp, quote, dquote, *buf; enum { STR, VAR, WHITE } state; ac = *argc = 0; - quote = 0; + dquote = quote = 0; if (!str || (p = copy = backslash(str)) == NULL) return 1; /* Initialize vector and state */ clean(); state = STR; buf = (char *)malloc(PARSE_BUFSIZE); token = 0; /* And awaaaaaaaaay we go! */ while (*p) { switch (state) { case STR: if ((*p == '\\') && p[1]) { p++; PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); buf[i++] = *p++; } else if (isquote(*p)) { quote = quote ? 0 : *p; - ++p; - } - else if (isspace(*p) && !quote) { + if (dquote) { /* keep quote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else + ++p; + } else if (isdquote(*p)) { + dquote = dquote ? 0 : *p; + if (quote) { /* keep dquote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else + ++p; + } else if (isspace(*p) && !quote && !dquote) { state = WHITE; if (i) { buf[i] = '\0'; PARSE_FAIL(insert(&ac, buf)); i = 0; } ++p; - } else if (*p == '$') { + } else if (*p == '$' && !quote) { token = isdelim(*(p + 1)); if (token) p += 2; else ++p; state = VAR; } else { PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); buf[i++] = *p++; } break; case WHITE: if (isspace(*p)) ++p; else state = STR; break; case VAR: if (token) { PARSE_FAIL((q = strchr(p, token)) == NULL); } else { q = p; while (*q && !isspace(*q)) ++q; } tmp = *q; *q = '\0'; if ((val = variable_lookup(p)) != NULL) { size_t len = strlen(val); strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1)); i += min(len, PARSE_BUFSIZE - 1); } *q = tmp; /* restore value */ p = q + (token ? 1 : 0); state = STR; break; } } + /* missing terminating ' or " */ + PARSE_FAIL(quote || dquote); /* If at end of token, add it */ if (i && state == STR) { buf[i] = '\0'; PARSE_FAIL(insert(&ac, buf)); } args[ac] = NULL; *argc = ac; *argv = (char **)malloc((sizeof(char *) * ac + 1)); bcopy(args, *argv, sizeof(char *) * ac + 1); free(buf); free(copy); return 0; } #define MAXARGS 20 /* Clean vector space */ static void clean(void) { int i; for (i = 0; i < MAXARGS; i++) { if (args[i] != NULL) { free(args[i]); args[i] = NULL; } } } static int insert(int *argcp, char *buf) { if (*argcp >= MAXARGS) return 1; args[(*argcp)++] = strdup(buf); return 0; } static char * variable_lookup(char *name) { /* XXX search "special variable" space first? */ return (char *)getenv(name); } Index: stable/11/sys/boot/common/ls.c =================================================================== --- stable/11/sys/boot/common/ls.c (revision 329009) +++ stable/11/sys/boot/common/ls.c (revision 329010) @@ -1,183 +1,187 @@ /* * $NetBSD: ls.c,v 1.3 1997/06/13 13:48:47 drochner Exp $ */ /*- * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * Copyright (c) 1996 * Matthias Drochner. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "bootstrap.h" static char typestr[] = "?fc?d?b? ?l?s?w"; static int ls_getdir(char **pathp); COMMAND_SET(ls, "ls", "list files", command_ls); static int command_ls(int argc, char *argv[]) { int fd; struct stat sb; struct dirent *d; char *buf, *path; char lbuf[128]; /* one line */ int result, ch; int verbose; result = CMD_OK; fd = -1; verbose = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "l")) != -1) { switch(ch) { case 'l': verbose = 1; break; case '?': default: /* getopt has already reported an error */ return(CMD_OK); } } argv += (optind - 1); argc -= (optind - 1); if (argc < 2) { path = ""; } else { path = argv[1]; } fd = ls_getdir(&path); if (fd == -1) { result = CMD_ERROR; goto out; } pager_open(); pager_output(path); pager_output("\n"); while ((d = readdirfd(fd)) != NULL) { if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { if (verbose) { /* stat the file, if possible */ sb.st_size = 0; buf = malloc(strlen(path) + strlen(d->d_name) + 2); sprintf(buf, "%s/%s", path, d->d_name); /* ignore return, could be symlink, etc. */ if (stat(buf, &sb)) sb.st_size = 0; free(buf); sprintf(lbuf, " %c %8d %s\n", typestr[d->d_type], (int)sb.st_size, d->d_name); } else { sprintf(lbuf, " %c %s\n", typestr[d->d_type], d->d_name); } if (pager_output(lbuf)) goto out; } } out: pager_close(); if (fd != -1) close(fd); if (path != NULL) free(path); return(result); } /* * Given (path) containing a vaguely reasonable path specification, return an fd * on the directory, and an allocated copy of the path to the directory. */ static int ls_getdir(char **pathp) { struct stat sb; int fd; const char *cp; char *path; fd = -1; /* one extra byte for a possible trailing slash required */ path = malloc(strlen(*pathp) + 2); strcpy(path, *pathp); /* Make sure the path is respectable to begin with */ if (archsw.arch_getdev(NULL, path, &cp)) { - sprintf(command_errbuf, "bad path '%s'", path); + snprintf(command_errbuf, sizeof(command_errbuf), + "bad path '%s'", path); goto out; } /* If there's no path on the device, assume '/' */ if (*cp == 0) strcat(path, "/"); fd = open(path, O_RDONLY); if (fd < 0) { - sprintf(command_errbuf, "open '%s' failed: %s", path, strerror(errno)); + snprintf(command_errbuf, sizeof(command_errbuf), + "open '%s' failed: %s", path, strerror(errno)); goto out; } if (fstat(fd, &sb) < 0) { - sprintf(command_errbuf, "stat failed: %s", strerror(errno)); + snprintf(command_errbuf, sizeof(command_errbuf), + "stat failed: %s", strerror(errno)); goto out; } if (!S_ISDIR(sb.st_mode)) { - sprintf(command_errbuf, "%s: %s", path, strerror(ENOTDIR)); + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: %s", path, strerror(ENOTDIR)); goto out; } *pathp = path; return(fd); out: free(path); *pathp = NULL; if (fd != -1) close(fd); return(-1); } Index: stable/11/sys/boot/common/module.c =================================================================== --- stable/11/sys/boot/common/module.c (revision 329009) +++ stable/11/sys/boot/common/module.c (revision 329010) @@ -1,1082 +1,1095 @@ /*- * 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$"); /* * file/module function dispatcher, support, etc. */ #include #include #include #include #include #include #include #include "bootstrap.h" #define MDIR_REMOVED 0x0001 #define MDIR_NOHINTS 0x0002 struct moduledir { char *d_path; /* path of modules directory */ u_char *d_hints; /* content of linker.hints file */ int d_hintsz; /* size of hints data */ int d_flags; STAILQ_ENTRY(moduledir) d_link; }; static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result); static int file_load_dependencies(struct preloaded_file *base_mod); static char * file_search(const char *name, char **extlist); static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo); static int file_havepath(const char *name); static char *mod_searchmodule(char *name, struct mod_depend *verinfo); static void file_insert_tail(struct preloaded_file *mp); struct file_metadata* metadata_next(struct file_metadata *base_mp, int type); static void moduledir_readhints(struct moduledir *mdp); static void moduledir_rebuild(void); /* load address should be tweaked by first module loaded (kernel) */ static vm_offset_t loadaddr = 0; #if defined(LOADER_FDT_SUPPORT) static const char *default_searchpath = "/boot/kernel;/boot/modules;/boot/dtb"; #else static const char *default_searchpath ="/boot/kernel;/boot/modules"; #endif static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list); struct preloaded_file *preloaded_files = NULL; static char *kld_ext_list[] = { ".ko", "", ".debug", NULL }; /* * load an object, either a disk file or code module. * * To load a file, the syntax is: * * load -t * * code modules are loaded as: * * load */ COMMAND_SET(load, "load", "load a kernel or module", command_load); static int command_load(int argc, char *argv[]) { struct preloaded_file *fp; char *typestr; int dofile, dokld, ch, error; dokld = dofile = 0; optind = 1; optreset = 1; typestr = NULL; if (argc == 1) { command_errmsg = "no filename specified"; return (CMD_CRIT); } while ((ch = getopt(argc, argv, "kt:")) != -1) { switch(ch) { case 'k': dokld = 1; break; case 't': typestr = optarg; dofile = 1; break; case '?': default: /* getopt has already reported an error */ return (CMD_OK); } } argv += (optind - 1); argc -= (optind - 1); /* * Request to load a raw file? */ if (dofile) { if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) { command_errmsg = "invalid load type"; return (CMD_CRIT); } fp = file_findfile(argv[1], typestr); if (fp) { - sprintf(command_errbuf, "warning: file '%s' already loaded", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "warning: file '%s' already loaded", argv[1]); return (CMD_WARN); } if (file_loadraw(argv[1], typestr, 1) != NULL) return (CMD_OK); /* Failing to load mfs_root is never going to end well! */ if (strcmp("mfs_root", typestr) == 0) return (CMD_FATAL); return (CMD_ERROR); } /* * Do we have explicit KLD load ? */ if (dokld || file_havepath(argv[1])) { error = mod_loadkld(argv[1], argc - 2, argv + 2); if (error == EEXIST) { - sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "warning: KLD '%s' already loaded", argv[1]); return (CMD_WARN); } return (error == 0 ? CMD_OK : CMD_CRIT); } /* * Looks like a request for a module. */ error = mod_load(argv[1], NULL, argc - 2, argv + 2); if (error == EEXIST) { - sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]); + snprintf(command_errbuf, sizeof(command_errbuf), + "warning: module '%s' already loaded", argv[1]); return (CMD_WARN); } return (error == 0 ? CMD_OK : CMD_CRIT); } #ifdef LOADER_GELI_SUPPORT COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli); static int command_load_geli(int argc, char *argv[]) { char typestr[80]; char *cp; int ch, num; if (argc < 3) { command_errmsg = "usage is [-n key#] "; return(CMD_ERROR); } num = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "n:")) != -1) { switch(ch) { case 'n': num = strtol(optarg, &cp, 0); if (cp == optarg) { - sprintf(command_errbuf, "bad key index '%s'", optarg); + snprintf(command_errbuf, sizeof(command_errbuf), + "bad key index '%s'", optarg); return(CMD_ERROR); } break; case '?': default: /* getopt has already reported an error */ return(CMD_OK); } } argv += (optind - 1); argc -= (optind - 1); sprintf(typestr, "%s:geli_keyfile%d", argv[1], num); return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR); } #endif void unload(void) { struct preloaded_file *fp; while (preloaded_files != NULL) { fp = preloaded_files; preloaded_files = preloaded_files->f_next; file_discard(fp); } loadaddr = 0; unsetenv("kernelname"); } COMMAND_SET(unload, "unload", "unload all modules", command_unload); static int command_unload(int argc, char *argv[]) { unload(); return(CMD_OK); } COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); static int command_lsmod(int argc, char *argv[]) { struct preloaded_file *fp; struct kernel_module *mp; struct file_metadata *md; char lbuf[80]; int ch, verbose, ret = 0; verbose = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "v")) != -1) { switch(ch) { case 'v': verbose = 1; break; case '?': default: /* getopt has already reported an error */ return(CMD_OK); } } pager_open(); for (fp = preloaded_files; fp; fp = fp->f_next) { snprintf(lbuf, sizeof(lbuf), " %p: ", (void *) fp->f_addr); pager_output(lbuf); pager_output(fp->f_name); snprintf(lbuf, sizeof(lbuf), " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size); if (pager_output(lbuf)) break; if (fp->f_args != NULL) { pager_output(" args: "); pager_output(fp->f_args); if (pager_output("\n")) break; } if (fp->f_modules) { pager_output(" modules: "); for (mp = fp->f_modules; mp; mp = mp->m_next) { snprintf(lbuf, sizeof(lbuf), "%s.%d ", mp->m_name, mp->m_version); pager_output(lbuf); } if (pager_output("\n")) break; } if (verbose) { /* XXX could add some formatting smarts here to display some better */ for (md = fp->f_metadata; md != NULL; md = md->md_next) { snprintf(lbuf, sizeof(lbuf), " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size); if (pager_output(lbuf)) break; } } if (ret) break; } pager_close(); return(CMD_OK); } /* * File level interface, functions file_* */ int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) { static int last_file_format = 0; struct preloaded_file *fp; int error; int i; if (archsw.arch_loadaddr != NULL) dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); error = EFTYPE; for (i = last_file_format, fp = NULL; file_formats[i] && fp == NULL; i++) { error = (file_formats[i]->l_load)(filename, dest, &fp); if (error == 0) { fp->f_loader = last_file_format = i; /* remember the loader */ *result = fp; break; } else if (last_file_format == i && i != 0) { /* Restart from the beginning */ i = -1; last_file_format = 0; fp = NULL; continue; } if (error == EFTYPE) continue; /* Unknown to this handler? */ if (error) { - sprintf(command_errbuf, "can't load file '%s': %s", - filename, strerror(error)); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't load file '%s': %s", filename, strerror(error)); break; } } return (error); } static int file_load_dependencies(struct preloaded_file *base_file) { struct file_metadata *md; struct preloaded_file *fp; struct mod_depend *verinfo; struct kernel_module *mp; char *dmodname; int error; md = file_findmetadata(base_file, MODINFOMD_DEPLIST); if (md == NULL) return (0); error = 0; do { verinfo = (struct mod_depend*)md->md_data; dmodname = (char *)(verinfo + 1); if (file_findmodule(NULL, dmodname, verinfo) == NULL) { printf("loading required module '%s'\n", dmodname); error = mod_load(dmodname, verinfo, 0, NULL); if (error) break; /* * If module loaded via kld name which isn't listed * in the linker.hints file, we should check if it have * required version. */ mp = file_findmodule(NULL, dmodname, verinfo); if (mp == NULL) { - sprintf(command_errbuf, "module '%s' exists but with wrong version", - dmodname); + snprintf(command_errbuf, sizeof(command_errbuf), + "module '%s' exists but with wrong version", dmodname); error = ENOENT; break; } } md = metadata_next(md, MODINFOMD_DEPLIST); } while (md); if (!error) return (0); /* Load failed; discard everything */ while (base_file != NULL) { fp = base_file; base_file = base_file->f_next; file_discard(fp); } return (error); } /* * We've been asked to load (fname) as (type), so just suck it in, * no arguments or anything. */ struct preloaded_file * file_loadraw(const char *fname, char *type, int insert) { struct preloaded_file *fp; char *name; int fd, got; vm_offset_t laddr; /* We can't load first */ if ((file_findfile(NULL, NULL)) == NULL) { command_errmsg = "can't load file before kernel"; return(NULL); } /* locate the file on the load path */ name = file_search(fname, NULL); if (name == NULL) { - sprintf(command_errbuf, "can't find '%s'", fname); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't find '%s'", fname); return(NULL); } if ((fd = open(name, O_RDONLY)) < 0) { - sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't open '%s': %s", name, strerror(errno)); free(name); return(NULL); } if (archsw.arch_loadaddr != NULL) loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); printf("%s ", name); laddr = loadaddr; for (;;) { /* read in 4k chunks; size is not really important */ got = archsw.arch_readin(fd, laddr, 4096); if (got == 0) /* end of file */ break; if (got < 0) { /* error */ - sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno)); + snprintf(command_errbuf, sizeof(command_errbuf), + "error reading '%s': %s", name, strerror(errno)); free(name); close(fd); return(NULL); } laddr += got; } printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr)); /* Looks OK so far; create & populate control structure */ fp = file_alloc(); fp->f_name = strdup(name); fp->f_type = strdup(type); fp->f_args = NULL; fp->f_metadata = NULL; fp->f_loader = -1; fp->f_addr = loadaddr; fp->f_size = laddr - loadaddr; /* recognise space consumption */ loadaddr = laddr; /* Add to the list of loaded files */ if (insert != 0) file_insert_tail(fp); close(fd); return(fp); } /* * Load the module (name), pass it (argc),(argv), add container file * to the list of loaded files. * If module is already loaded just assign new argc/argv. */ int mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[]) { struct kernel_module *mp; int err; char *filename; if (file_havepath(modname)) { printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname); return (mod_loadkld(modname, argc, argv)); } /* see if module is already loaded */ mp = file_findmodule(NULL, modname, verinfo); if (mp) { #ifdef moduleargs if (mp->m_args) free(mp->m_args); mp->m_args = unargv(argc, argv); #endif - sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name); + snprintf(command_errbuf, sizeof(command_errbuf), + "warning: module '%s' already loaded", mp->m_name); return (0); } /* locate file with the module on the search path */ filename = mod_searchmodule(modname, verinfo); if (filename == NULL) { - sprintf(command_errbuf, "can't find '%s'", modname); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't find '%s'", modname); return (ENOENT); } err = mod_loadkld(filename, argc, argv); return (err); } /* * Load specified KLD. If path is omitted, then try to locate it via * search path. */ int mod_loadkld(const char *kldname, int argc, char *argv[]) { struct preloaded_file *fp, *last_file; int err; char *filename; /* * Get fully qualified KLD name */ filename = file_search(kldname, kld_ext_list); if (filename == NULL) { - sprintf(command_errbuf, "can't find '%s'", kldname); + snprintf(command_errbuf, sizeof(command_errbuf), + "can't find '%s'", kldname); return (ENOENT); } /* * Check if KLD already loaded */ fp = file_findfile(filename, NULL); if (fp) { - sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename); + snprintf(command_errbuf, sizeof(command_errbuf), + "warning: KLD '%s' already loaded", filename); free(filename); return (0); } for (last_file = preloaded_files; last_file != NULL && last_file->f_next != NULL; last_file = last_file->f_next) ; do { err = file_load(filename, loadaddr, &fp); if (err) break; fp->f_args = unargv(argc, argv); loadaddr = fp->f_addr + fp->f_size; file_insert_tail(fp); /* Add to the list of loaded files */ if (file_load_dependencies(fp) != 0) { err = ENOENT; last_file->f_next = NULL; loadaddr = last_file->f_addr + last_file->f_size; fp = NULL; break; } } while(0); - if (err == EFTYPE) - sprintf(command_errbuf, "don't know how to load module '%s'", filename); + if (err == EFTYPE) { + snprintf(command_errbuf, sizeof(command_errbuf), + "don't know how to load module '%s'", filename); + } if (err && fp) file_discard(fp); free(filename); return (err); } /* * Find a file matching (name) and (type). * NULL may be passed as a wildcard to either. */ struct preloaded_file * file_findfile(const char *name, const char *type) { struct preloaded_file *fp; for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { if (((name == NULL) || !strcmp(name, fp->f_name)) && ((type == NULL) || !strcmp(type, fp->f_type))) break; } return (fp); } /* * Find a module matching (name) inside of given file. * NULL may be passed as a wildcard. */ struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo) { struct kernel_module *mp, *best; int bestver, mver; if (fp == NULL) { for (fp = preloaded_files; fp; fp = fp->f_next) { mp = file_findmodule(fp, modname, verinfo); if (mp) return (mp); } return (NULL); } best = NULL; bestver = 0; for (mp = fp->f_modules; mp; mp = mp->m_next) { if (strcmp(modname, mp->m_name) == 0) { if (verinfo == NULL) return (mp); mver = mp->m_version; if (mver == verinfo->md_ver_preferred) return (mp); if (mver >= verinfo->md_ver_minimum && mver <= verinfo->md_ver_maximum && mver > bestver) { best = mp; bestver = mver; } } } return (best); } /* * Make a copy of (size) bytes of data from (p), and associate them as * metadata of (type) to the module (mp). */ void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) { struct file_metadata *md; md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size); md->md_size = size; md->md_type = type; bcopy(p, md->md_data, size); md->md_next = fp->f_metadata; fp->f_metadata = md; } /* * Find a metadata object of (type) associated with the file (fp) */ struct file_metadata * file_findmetadata(struct preloaded_file *fp, int type) { struct file_metadata *md; for (md = fp->f_metadata; md != NULL; md = md->md_next) if (md->md_type == type) break; return(md); } /* * Remove all metadata from the file. */ void file_removemetadata(struct preloaded_file *fp) { struct file_metadata *md, *next; for (md = fp->f_metadata; md != NULL; md = next) { next = md->md_next; free(md); } fp->f_metadata = NULL; } struct file_metadata * metadata_next(struct file_metadata *md, int type) { if (md == NULL) return (NULL); while((md = md->md_next) != NULL) if (md->md_type == type) break; return (md); } static char *emptyextlist[] = { "", NULL }; /* * Check if the given file is in place and return full path to it. */ static char * file_lookup(const char *path, const char *name, int namelen, char **extlist) { struct stat st; char *result, *cp, **cpp; int pathlen, extlen, len; pathlen = strlen(path); extlen = 0; if (extlist == NULL) extlist = emptyextlist; for (cpp = extlist; *cpp; cpp++) { len = strlen(*cpp); if (len > extlen) extlen = len; } result = malloc(pathlen + namelen + extlen + 2); if (result == NULL) return (NULL); bcopy(path, result, pathlen); if (pathlen > 0 && result[pathlen - 1] != '/') result[pathlen++] = '/'; cp = result + pathlen; bcopy(name, cp, namelen); cp += namelen; for (cpp = extlist; *cpp; cpp++) { strcpy(cp, *cpp); if (stat(result, &st) == 0 && S_ISREG(st.st_mode)) return result; } free(result); return NULL; } /* * Check if file name have any qualifiers */ static int file_havepath(const char *name) { const char *cp; archsw.arch_getdev(NULL, name, &cp); return (cp != name || strchr(name, '/') != NULL); } /* * Attempt to find the file (name) on the module searchpath. * If (name) is qualified in any way, we simply check it and * return it or NULL. If it is not qualified, then we attempt * to construct a path using entries in the environment variable * module_path. * * The path we return a pointer to need never be freed, as we manage * it internally. */ static char * file_search(const char *name, char **extlist) { struct moduledir *mdp; struct stat sb; char *result; int namelen; /* Don't look for nothing */ if (name == NULL) return(NULL); if (*name == 0) return(strdup(name)); if (file_havepath(name)) { /* Qualified, so just see if it exists */ if (stat(name, &sb) == 0) return(strdup(name)); return(NULL); } moduledir_rebuild(); result = NULL; namelen = strlen(name); STAILQ_FOREACH(mdp, &moduledir_list, d_link) { result = file_lookup(mdp->d_path, name, namelen, extlist); if (result) break; } return(result); } #define INT_ALIGN(base, ptr) ptr = \ (base) + roundup2((ptr) - (base), sizeof(int)) static char * mod_search_hints(struct moduledir *mdp, const char *modname, struct mod_depend *verinfo) { u_char *cp, *recptr, *bufend, *best; char *result; int *intp, bestver, blen, clen, found, ival, modnamelen, reclen; moduledir_readhints(mdp); modnamelen = strlen(modname); found = 0; result = NULL; bestver = 0; if (mdp->d_hints == NULL) goto bad; recptr = mdp->d_hints; bufend = recptr + mdp->d_hintsz; clen = blen = 0; best = cp = NULL; while (recptr < bufend && !found) { intp = (int*)recptr; reclen = *intp++; ival = *intp++; cp = (u_char*)intp; switch (ival) { case MDT_VERSION: clen = *cp++; if (clen != modnamelen || bcmp(cp, modname, clen) != 0) break; cp += clen; INT_ALIGN(mdp->d_hints, cp); ival = *(int*)cp; cp += sizeof(int); clen = *cp++; if (verinfo == NULL || ival == verinfo->md_ver_preferred) { found = 1; break; } if (ival >= verinfo->md_ver_minimum && ival <= verinfo->md_ver_maximum && ival > bestver) { bestver = ival; best = cp; blen = clen; } break; default: break; } recptr += reclen + sizeof(int); } /* * Finally check if KLD is in the place */ if (found) result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL); else if (best) result = file_lookup(mdp->d_path, (const char *)best, blen, NULL); bad: /* * If nothing found or hints is absent - fallback to the old way * by using "kldname[.ko]" as module name. */ if (!found && !bestver && result == NULL) result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list); return result; } /* * Attempt to locate the file containing the module (name) */ static char * mod_searchmodule(char *name, struct mod_depend *verinfo) { struct moduledir *mdp; char *result; moduledir_rebuild(); /* * Now we ready to lookup module in the given directories */ result = NULL; STAILQ_FOREACH(mdp, &moduledir_list, d_link) { result = mod_search_hints(mdp, name, verinfo); if (result) break; } return(result); } int file_addmodule(struct preloaded_file *fp, char *modname, int version, struct kernel_module **newmp) { struct kernel_module *mp; struct mod_depend mdepend; bzero(&mdepend, sizeof(mdepend)); mdepend.md_ver_preferred = version; mp = file_findmodule(fp, modname, &mdepend); if (mp) return (EEXIST); mp = malloc(sizeof(struct kernel_module)); if (mp == NULL) return (ENOMEM); bzero(mp, sizeof(struct kernel_module)); mp->m_name = strdup(modname); mp->m_version = version; mp->m_fp = fp; mp->m_next = fp->f_modules; fp->f_modules = mp; if (newmp) *newmp = mp; return (0); } /* * Throw a file away */ void file_discard(struct preloaded_file *fp) { struct file_metadata *md, *md1; struct kernel_module *mp, *mp1; if (fp == NULL) return; md = fp->f_metadata; while (md) { md1 = md; md = md->md_next; free(md1); } mp = fp->f_modules; while (mp) { if (mp->m_name) free(mp->m_name); mp1 = mp; mp = mp->m_next; free(mp1); } if (fp->f_name != NULL) free(fp->f_name); if (fp->f_type != NULL) free(fp->f_type); if (fp->f_args != NULL) free(fp->f_args); free(fp); } /* * Allocate a new file; must be used instead of malloc() * to ensure safe initialisation. */ struct preloaded_file * file_alloc(void) { struct preloaded_file *fp; if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) { bzero(fp, sizeof(struct preloaded_file)); } return (fp); } /* * Add a module to the chain */ static void file_insert_tail(struct preloaded_file *fp) { struct preloaded_file *cm; /* Append to list of loaded file */ fp->f_next = NULL; if (preloaded_files == NULL) { preloaded_files = fp; } else { for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) ; cm->f_next = fp; } } static char * moduledir_fullpath(struct moduledir *mdp, const char *fname) { char *cp; cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2); if (cp == NULL) return NULL; strcpy(cp, mdp->d_path); strcat(cp, "/"); strcat(cp, fname); return (cp); } /* * Read linker.hints file into memory performing some sanity checks. */ static void moduledir_readhints(struct moduledir *mdp) { struct stat st; char *path; int fd, size, version; if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS)) return; path = moduledir_fullpath(mdp, "linker.hints"); if (stat(path, &st) != 0 || st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) || st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) { free(path); mdp->d_flags |= MDIR_NOHINTS; return; } free(path); size = read(fd, &version, sizeof(version)); if (size != sizeof(version) || version != LINKER_HINTS_VERSION) goto bad; size = st.st_size - size; mdp->d_hints = malloc(size); if (mdp->d_hints == NULL) goto bad; if (read(fd, mdp->d_hints, size) != size) goto bad; mdp->d_hintsz = size; close(fd); return; bad: close(fd); if (mdp->d_hints) { free(mdp->d_hints); mdp->d_hints = NULL; } mdp->d_flags |= MDIR_NOHINTS; return; } /* * Extract directories from the ';' separated list, remove duplicates. */ static void moduledir_rebuild(void) { struct moduledir *mdp, *mtmp; const char *path, *cp, *ep; size_t cplen; path = getenv("module_path"); if (path == NULL) path = default_searchpath; /* * Rebuild list of module directories if it changed */ STAILQ_FOREACH(mdp, &moduledir_list, d_link) mdp->d_flags |= MDIR_REMOVED; for (ep = path; *ep != 0; ep++) { cp = ep; for (; *ep != 0 && *ep != ';'; ep++) ; /* * Ignore trailing slashes */ for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--) ; STAILQ_FOREACH(mdp, &moduledir_list, d_link) { if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0) continue; mdp->d_flags &= ~MDIR_REMOVED; break; } if (mdp == NULL) { mdp = malloc(sizeof(*mdp) + cplen + 1); if (mdp == NULL) return; mdp->d_path = (char*)(mdp + 1); bcopy(cp, mdp->d_path, cplen); mdp->d_path[cplen] = 0; mdp->d_hints = NULL; mdp->d_flags = 0; STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link); } if (*ep == 0) break; } /* * Delete unused directories if any */ mdp = STAILQ_FIRST(&moduledir_list); while (mdp) { if ((mdp->d_flags & MDIR_REMOVED) == 0) { mdp = STAILQ_NEXT(mdp, d_link); } else { if (mdp->d_hints) free(mdp->d_hints); mtmp = mdp; mdp = STAILQ_NEXT(mdp, d_link); STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link); free(mtmp); } } return; } Index: stable/11/sys/boot/common/ufsread.c =================================================================== --- stable/11/sys/boot/common/ufsread.c (revision 329009) +++ stable/11/sys/boot/common/ufsread.c (revision 329010) @@ -1,326 +1,326 @@ /*- * Copyright (c) 2002 McAfee, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Marshall * Kirk McKusick and McAfee Research,, the Security Research Division of * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as * part of the DARPA CHATS research program * * 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. */ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #ifdef UFS_SMALL_CGBASE /* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can support both UFS1 and UFS2. */ #undef cgbase #define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) #endif typedef uint32_t ufs_ino_t; /* * We use 4k `virtual' blocks for filesystem data, whatever the actual * filesystem block size. FFS blocks are always a multiple of 4k. */ #define VBLKSHIFT 12 #define VBLKSIZE (1 << VBLKSHIFT) #define VBLKMASK (VBLKSIZE - 1) #define DBPERVBLK (VBLKSIZE / DEV_BSIZE) #define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) #define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) #define INO_TO_VBA(fs, ipervblk, x) \ (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) #define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) #define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ ((off) / VBLKSIZE) * DBPERVBLK) #define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) /* Buffers that must not span a 64k boundary. */ struct dmadat { char blkbuf[VBLKSIZE]; /* filesystem blocks */ char indbuf[VBLKSIZE]; /* indir blocks */ char sbbuf[SBLOCKSIZE]; /* superblock */ char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ }; static struct dmadat *dmadat; static ufs_ino_t lookup(const char *); static ssize_t fsread(ufs_ino_t, void *, size_t); static uint8_t ls, dsk_meta; static uint32_t fs_off; static __inline uint8_t fsfind(const char *name, ufs_ino_t * ino) { static char buf[DEV_BSIZE]; - struct direct *d; + static struct direct d; char *s; ssize_t n; fs_off = 0; while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) for (s = buf; s < buf + DEV_BSIZE;) { - d = (void *)s; + memcpy(&d, s, sizeof(struct direct)); if (ls) - printf("%s ", d->d_name); - else if (!strcmp(name, d->d_name)) { - *ino = d->d_ino; - return d->d_type; + printf("%s ", d.d_name); + else if (!strcmp(name, d.d_name)) { + *ino = d.d_ino; + return d.d_type; } - s += d->d_reclen; + s += d.d_reclen; } if (n != -1 && ls) printf("\n"); return 0; } static ufs_ino_t lookup(const char *path) { static char name[MAXNAMLEN + 1]; const char *s; ufs_ino_t ino; ssize_t n; uint8_t dt; ino = ROOTINO; dt = DT_DIR; for (;;) { if (*path == '/') path++; if (!*path) break; for (s = path; *s && *s != '/'; s++); if ((n = s - path) > MAXNAMLEN) return 0; ls = *path == '?' && n == 1 && !*s; memcpy(name, path, n); name[n] = 0; if (dt != DT_DIR) { printf("%s: not a directory.\n", name); return (0); } if ((dt = fsfind(name, &ino)) <= 0) break; path = s; } return dt == DT_REG ? ino : 0; } /* * Possible superblock locations ordered from most to least likely. */ static int sblock_try[] = SBLOCKSEARCH; #if defined(UFS2_ONLY) #define DIP(field) dp2.field #elif defined(UFS1_ONLY) #define DIP(field) dp1.field #else #define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field #endif static ssize_t fsread_size(ufs_ino_t inode, void *buf, size_t nbyte, size_t *fsizep) { #ifndef UFS2_ONLY static struct ufs1_dinode dp1; ufs1_daddr_t addr1; #endif #ifndef UFS1_ONLY static struct ufs2_dinode dp2; #endif static struct fs fs; static ufs_ino_t inomap; char *blkbuf; void *indbuf; char *s; size_t n, nb, size, off, vboff; ufs_lbn_t lbn; ufs2_daddr_t addr2, vbaddr; static ufs2_daddr_t blkmap, indmap; u_int u; /* Basic parameter validation. */ if ((buf == NULL && nbyte != 0) || dmadat == NULL) return (-1); blkbuf = dmadat->blkbuf; indbuf = dmadat->indbuf; /* * Force probe if inode is zero to ensure we have a valid fs, otherwise * when probing multiple paritions, reads from subsequent parititions * will incorrectly succeed. */ if (!dsk_meta || inode == 0) { inomap = 0; dsk_meta = 0; for (n = 0; sblock_try[n] != -1; n++) { if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, SBLOCKSIZE / DEV_BSIZE)) return -1; memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); if (( #if defined(UFS1_ONLY) fs.fs_magic == FS_UFS1_MAGIC #elif defined(UFS2_ONLY) (fs.fs_magic == FS_UFS2_MAGIC && fs.fs_sblockloc == sblock_try[n]) #else fs.fs_magic == FS_UFS1_MAGIC || (fs.fs_magic == FS_UFS2_MAGIC && fs.fs_sblockloc == sblock_try[n]) #endif ) && fs.fs_bsize <= MAXBSIZE && fs.fs_bsize >= (int32_t)sizeof(struct fs)) break; } if (sblock_try[n] == -1) { return -1; } dsk_meta++; } else memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); if (!inode) return 0; if (inomap != inode) { n = IPERVBLK(&fs); if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) return -1; n = INO_TO_VBO(n, inode); #if defined(UFS1_ONLY) memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, sizeof(dp1)); #elif defined(UFS2_ONLY) memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, sizeof(dp2)); #else if (fs.fs_magic == FS_UFS1_MAGIC) memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, sizeof(dp1)); else memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, sizeof(dp2)); #endif inomap = inode; fs_off = 0; blkmap = indmap = 0; } s = buf; size = DIP(di_size); n = size - fs_off; if (nbyte > n) nbyte = n; nb = nbyte; while (nb) { lbn = lblkno(&fs, fs_off); off = blkoff(&fs, fs_off); if (lbn < NDADDR) { addr2 = DIP(di_db[lbn]); } else if (lbn < NDADDR + NINDIR(&fs)) { n = INDIRPERVBLK(&fs); addr2 = DIP(di_ib[0]); u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; vbaddr = fsbtodb(&fs, addr2) + u; if (indmap != vbaddr) { if (dskread(indbuf, vbaddr, DBPERVBLK)) return -1; indmap = vbaddr; } n = (lbn - NDADDR) & (n - 1); #if defined(UFS1_ONLY) memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, sizeof(ufs1_daddr_t)); addr2 = addr1; #elif defined(UFS2_ONLY) memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, sizeof(ufs2_daddr_t)); #else if (fs.fs_magic == FS_UFS1_MAGIC) { memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, sizeof(ufs1_daddr_t)); addr2 = addr1; } else memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, sizeof(ufs2_daddr_t)); #endif } else return -1; vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; vboff = off & VBLKMASK; n = sblksize(&fs, (off_t)size, lbn) - (off & ~VBLKMASK); if (n > VBLKSIZE) n = VBLKSIZE; if (blkmap != vbaddr) { if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) return -1; blkmap = vbaddr; } n -= vboff; if (n > nb) n = nb; memcpy(s, blkbuf + vboff, n); s += n; fs_off += n; nb -= n; } if (fsizep != NULL) *fsizep = size; return nbyte; } static ssize_t fsread(ufs_ino_t inode, void *buf, size_t nbyte) { return fsread_size(inode, buf, nbyte, NULL); } Index: stable/11/sys/boot/efi/boot1/boot1.c =================================================================== --- stable/11/sys/boot/efi/boot1/boot1.c (revision 329009) +++ stable/11/sys/boot/efi/boot1/boot1.c (revision 329010) @@ -1,717 +1,718 @@ /*- * Copyright (c) 1998 Robert Nordier * All rights reserved. * Copyright (c) 2001 Robert Drehmel * All rights reserved. * Copyright (c) 2014 Nathan Whitehorn * All rights reserved. * Copyright (c) 2015 Eric McCorkle * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "boot_module.h" #include "paths.h" static const boot_module_t *boot_modules[] = { #ifdef EFI_ZFS_BOOT &zfs_module, #endif #ifdef EFI_UFS_BOOT &ufs_module #endif }; #define NUM_BOOT_MODULES nitems(boot_modules) /* The initial number of handles used to query EFI for partitions. */ #define NUM_HANDLES_INIT 24 EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); EFI_SYSTEM_TABLE *systab; EFI_BOOT_SERVICES *bs; static EFI_HANDLE *image; static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; /* * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from * EFI methods. */ void * Malloc(size_t len, const char *file __unused, int line __unused) { void *out; if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) return (out); return (NULL); } void Free(void *buf, const char *file __unused, int line __unused) { - (void)bs->FreePool(buf); + if (buf != NULL) + (void)bs->FreePool(buf); } /* * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, * FALSE otherwise. */ static BOOLEAN nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) { int len; if (imgpath == NULL || imgpath->Type != devpath->Type || imgpath->SubType != devpath->SubType) return (FALSE); len = DevicePathNodeLength(imgpath); if (len != DevicePathNodeLength(devpath)) return (FALSE); return (memcmp(imgpath, devpath, (size_t)len) == 0); } /* * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes * in imgpath and devpath match up to their respective occurrences of a * media node, FALSE otherwise. */ static BOOLEAN device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) { if (imgpath == NULL) return (FALSE); while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) return (TRUE); if (!nodes_match(imgpath, devpath)) return (FALSE); imgpath = NextDevicePathNode(imgpath); devpath = NextDevicePathNode(devpath); } return (FALSE); } /* * devpath_last returns the last non-path end node in devpath. */ static EFI_DEVICE_PATH * devpath_last(EFI_DEVICE_PATH *devpath) { while (!IsDevicePathEnd(NextDevicePathNode(devpath))) devpath = NextDevicePathNode(devpath); return (devpath); } /* * devpath_node_str is a basic output method for a devpath node which * only understands a subset of the available sub types. * * If we switch to UEFI 2.x then we should update it to use: * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. */ static int devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) { switch (devpath->Type) { case MESSAGING_DEVICE_PATH: switch (devpath->SubType) { case MSG_ATAPI_DP: { ATAPI_DEVICE_PATH *atapi; atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "ata(%s,%s,0x%x)", (atapi->PrimarySecondary == 1) ? "Sec" : "Pri", (atapi->SlaveMaster == 1) ? "Slave" : "Master", atapi->Lun); } case MSG_USB_DP: { USB_DEVICE_PATH *usb; usb = (USB_DEVICE_PATH *)devpath; return snprintf(buf, size, "usb(0x%02x,0x%02x)", usb->ParentPortNumber, usb->InterfaceNumber); } case MSG_SCSI_DP: { SCSI_DEVICE_PATH *scsi; scsi = (SCSI_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "scsi(0x%02x,0x%02x)", scsi->Pun, scsi->Lun); } case MSG_SATA_DP: { SATA_DEVICE_PATH *sata; sata = (SATA_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", sata->HBAPortNumber, sata->PortMultiplierPortNumber, sata->Lun); } default: return snprintf(buf, size, "msg(0x%02x)", devpath->SubType); } break; case HARDWARE_DEVICE_PATH: switch (devpath->SubType) { case HW_PCI_DP: { PCI_DEVICE_PATH *pci; pci = (PCI_DEVICE_PATH *)devpath; return snprintf(buf, size, "pci(0x%02x,0x%02x)", pci->Device, pci->Function); } default: return snprintf(buf, size, "hw(0x%02x)", devpath->SubType); } break; case ACPI_DEVICE_PATH: { ACPI_HID_DEVICE_PATH *acpi; acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { switch (EISA_ID_TO_NUM(acpi->HID)) { case 0x0a03: return snprintf(buf, size, "pciroot(0x%x)", acpi->UID); case 0x0a08: return snprintf(buf, size, "pcieroot(0x%x)", acpi->UID); case 0x0604: return snprintf(buf, size, "floppy(0x%x)", acpi->UID); case 0x0301: return snprintf(buf, size, "keyboard(0x%x)", acpi->UID); case 0x0501: return snprintf(buf, size, "serial(0x%x)", acpi->UID); case 0x0401: return snprintf(buf, size, "parallelport(0x%x)", acpi->UID); default: return snprintf(buf, size, "acpi(pnp%04x,0x%x)", EISA_ID_TO_NUM(acpi->HID), acpi->UID); } } return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, acpi->UID); } case MEDIA_DEVICE_PATH: switch (devpath->SubType) { case MEDIA_CDROM_DP: { CDROM_DEVICE_PATH *cdrom; cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "cdrom(%x)", cdrom->BootEntry); } case MEDIA_HARDDRIVE_DP: { HARDDRIVE_DEVICE_PATH *hd; hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; return snprintf(buf, size, "hd(%x)", hd->PartitionNumber); } default: return snprintf(buf, size, "media(0x%02x)", devpath->SubType); } case BBS_DEVICE_PATH: return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); case END_DEVICE_PATH_TYPE: return (0); } return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, devpath->SubType); } /* * devpath_strlcat appends a text description of devpath to buf but not more * than size - 1 characters followed by NUL-terminator. */ int devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) { size_t len, used; const char *sep; sep = ""; used = 0; while (!IsDevicePathEnd(devpath)) { len = snprintf(buf, size - used, "%s", sep); used += len; if (used > size) return (used); buf += len; len = devpath_node_str(buf, size - used, devpath); used += len; if (used > size) return (used); buf += len; devpath = NextDevicePathNode(devpath); sep = ":"; } return (used); } /* * devpath_str is convenience method which returns the text description of * devpath using a static buffer, so it isn't thread safe! */ char * devpath_str(EFI_DEVICE_PATH *devpath) { static char buf[256]; devpath_strlcat(buf, sizeof(buf), devpath); return buf; } /* * load_loader attempts to load the loader image data. * * It tries each module and its respective devices, identified by mod->probe, * in order until a successful load occurs at which point it returns EFI_SUCCESS * and EFI_NOT_FOUND otherwise. * * Only devices which have preferred matching the preferred parameter are tried. */ static EFI_STATUS load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, size_t *bufsize, BOOLEAN preferred) { UINTN i; dev_info_t *dev; const boot_module_t *mod; for (i = 0; i < NUM_BOOT_MODULES; i++) { mod = boot_modules[i]; for (dev = mod->devices(); dev != NULL; dev = dev->next) { if (dev->preferred != preferred) continue; if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == EFI_SUCCESS) { *devinfop = dev; *modp = mod; return (EFI_SUCCESS); } } } return (EFI_NOT_FOUND); } /* * try_boot only returns if it fails to load the loader. If it succeeds * it simply boots, otherwise it returns the status of last EFI call. */ static EFI_STATUS try_boot(void) { size_t bufsize, loadersize, cmdsize; void *buf, *loaderbuf; char *cmd; dev_info_t *dev; const boot_module_t *mod; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); if (status != EFI_SUCCESS) { status = load_loader(&mod, &dev, &loaderbuf, &loadersize, FALSE); if (status != EFI_SUCCESS) { printf("Failed to load '%s'\n", PATH_LOADER_EFI); return (status); } } /* * Read in and parse the command line from /boot.config or /boot/config, * if present. We'll pass it the next stage via a simple ASCII * string. loader.efi has a hack for ASCII strings, so we'll use that to * keep the size down here. We only try to read the alternate file if * we get EFI_NOT_FOUND because all other errors mean that the boot_module * had troubles with the filesystem. We could return early, but we'll let * loading the actual kernel sort all that out. Since these files are * optional, we don't report errors in trying to read them. */ cmd = NULL; cmdsize = 0; status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); if (status == EFI_NOT_FOUND) status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); if (status == EFI_SUCCESS) { cmdsize = bufsize + 1; cmd = malloc(cmdsize); if (cmd == NULL) goto errout; memcpy(cmd, buf, bufsize); cmd[bufsize] = '\0'; free(buf); buf = NULL; } if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath), loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { printf("Failed to load image provided by %s, size: %zu, (%lu)\n", mod->name, loadersize, EFI_ERROR_CODE(status)); goto errout; } if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, (VOID**)&loaded_image)) != EFI_SUCCESS) { printf("Failed to query LoadedImage provided by %s (%lu)\n", mod->name, EFI_ERROR_CODE(status)); goto errout; } if (cmd != NULL) printf(" command args: %s\n", cmd); loaded_image->DeviceHandle = dev->devhandle; loaded_image->LoadOptionsSize = cmdsize; loaded_image->LoadOptions = cmd; DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF("."); DSTALL(1000000); DPRINTF(".\n"); if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != EFI_SUCCESS) { printf("Failed to start image provided by %s (%lu)\n", mod->name, EFI_ERROR_CODE(status)); loaded_image->LoadOptionsSize = 0; loaded_image->LoadOptions = NULL; } errout: if (cmd != NULL) free(cmd); if (buf != NULL) free(buf); if (loaderbuf != NULL) free(loaderbuf); return (status); } /* * probe_handle determines if the passed handle represents a logical partition * if it does it uses each module in order to probe it and if successful it * returns EFI_SUCCESS. */ static EFI_STATUS probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) { dev_info_t *devinfo; EFI_BLOCK_IO *blkio; EFI_DEVICE_PATH *devpath; EFI_STATUS status; UINTN i; /* Figure out if we're dealing with an actual partition. */ status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query DevicePath (%lu)\n", EFI_ERROR_CODE(status)); return (status); } DPRINTF("probing: %s\n", devpath_str(devpath)); status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); if (status == EFI_UNSUPPORTED) return (status); if (status != EFI_SUCCESS) { DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", EFI_ERROR_CODE(status)); return (status); } if (!blkio->Media->LogicalPartition) return (EFI_UNSUPPORTED); *preferred = device_paths_match(imgpath, devpath); /* Run through each module, see if it can load this partition */ for (i = 0; i < NUM_BOOT_MODULES; i++) { if ((status = bs->AllocatePool(EfiLoaderData, sizeof(*devinfo), (void **)&devinfo)) != EFI_SUCCESS) { DPRINTF("\nFailed to allocate devinfo (%lu)\n", EFI_ERROR_CODE(status)); continue; } devinfo->dev = blkio; devinfo->devpath = devpath; devinfo->devhandle = h; devinfo->devdata = NULL; devinfo->preferred = *preferred; devinfo->next = NULL; status = boot_modules[i]->probe(devinfo); if (status == EFI_SUCCESS) return (EFI_SUCCESS); (void)bs->FreePool(devinfo); } return (EFI_UNSUPPORTED); } /* * probe_handle_status calls probe_handle and outputs the returned status * of the call. */ static void probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) { EFI_STATUS status; BOOLEAN preferred; status = probe_handle(h, imgpath, &preferred); DPRINTF("probe: "); switch (status) { case EFI_UNSUPPORTED: printf("."); DPRINTF(" not supported\n"); break; case EFI_SUCCESS: if (preferred) { printf("%c", '*'); DPRINTF(" supported (preferred)\n"); } else { printf("%c", '+'); DPRINTF(" supported\n"); } break; default: printf("x"); DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); break; } DSTALL(500000); } EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) { EFI_HANDLE *handles; EFI_LOADED_IMAGE *img; EFI_DEVICE_PATH *imgpath; EFI_STATUS status; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; /* Basic initialization*/ systab = Xsystab; image = Ximage; bs = Xsystab->BootServices; /* Set up the console, so printf works. */ status = bs->LocateProtocol(&ConsoleControlGUID, NULL, (VOID **)&ConsoleControl); if (status == EFI_SUCCESS) (void)ConsoleControl->SetMode(ConsoleControl, EfiConsoleControlScreenText); /* * Reset the console and find the best text mode. */ conout = systab->ConOut; conout->Reset(conout, TRUE); max_dim = best_mode = 0; for (i = 0; ; i++) { status = conout->QueryMode(conout, i, &cols, &rows); if (EFI_ERROR(status)) break; if (cols * rows > max_dim) { max_dim = cols * rows; best_mode = i; } } if (max_dim > 0) conout->SetMode(conout, best_mode); conout->EnableCursor(conout, TRUE); conout->ClearScreen(conout); printf("\n>> FreeBSD EFI boot block\n"); printf(" Loader path: %s\n\n", PATH_LOADER_EFI); printf(" Initializing modules:"); for (i = 0; i < NUM_BOOT_MODULES; i++) { printf(" %s", boot_modules[i]->name); if (boot_modules[i]->init != NULL) boot_modules[i]->init(); } putchar('\n'); /* Get all the device handles */ hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) != EFI_SUCCESS) panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, EFI_ERROR_CODE(status)); status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, &hsize, handles); switch (status) { case EFI_SUCCESS: break; case EFI_BUFFER_TOO_SMALL: (void)bs->FreePool(handles); if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) != EFI_SUCCESS) { panic("Failed to allocate %zu handles (%lu)", hsize / sizeof(*handles), EFI_ERROR_CODE(status)); } status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, &hsize, handles); if (status != EFI_SUCCESS) panic("Failed to get device handles (%lu)\n", EFI_ERROR_CODE(status)); break; default: panic("Failed to get device handles (%lu)", EFI_ERROR_CODE(status)); } /* Scan all partitions, probing with all modules. */ nhandles = hsize / sizeof(*handles); printf(" Probing %zu block devices...", nhandles); DPRINTF("\n"); /* Determine the devpath of our image so we can prefer it. */ status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img); imgpath = NULL; if (status == EFI_SUCCESS) { status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID, (void **)&imgpath); if (status != EFI_SUCCESS) DPRINTF("Failed to get image DevicePath (%lu)\n", EFI_ERROR_CODE(status)); DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); } for (i = 0; i < nhandles; i++) probe_handle_status(handles[i], imgpath); printf(" done\n"); /* Status summary. */ for (i = 0; i < NUM_BOOT_MODULES; i++) { printf(" "); boot_modules[i]->status(); } try_boot(); /* If we get here, we're out of luck... */ panic("No bootable partitions found!"); } /* * add_device adds a device to the passed devinfo list. */ void add_device(dev_info_t **devinfop, dev_info_t *devinfo) { dev_info_t *dev; if (*devinfop == NULL) { *devinfop = devinfo; return; } for (dev = *devinfop; dev->next != NULL; dev = dev->next) ; dev->next = devinfo; } void panic(const char *fmt, ...) { va_list ap; printf("panic: "); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); while (1) {} } void putchar(int c) { CHAR16 buf[2]; if (c == '\n') { buf[0] = '\r'; buf[1] = 0; systab->ConOut->OutputString(systab->ConOut, buf); } buf[0] = c; buf[1] = 0; systab->ConOut->OutputString(systab->ConOut, buf); } Index: stable/11/sys/boot/efi/libefi/efi_console.c =================================================================== --- stable/11/sys/boot/efi/libefi/efi_console.c (revision 329009) +++ stable/11/sys/boot/efi/libefi/efi_console.c (revision 329010) @@ -1,498 +1,518 @@ /*- * Copyright (c) 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 "bootstrap.h" static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; static SIMPLE_INPUT_INTERFACE *conin; #ifdef TERM_EMU #define DEFAULT_FGCOLOR EFI_LIGHTGRAY #define DEFAULT_BGCOLOR EFI_BLACK #define MAXARGS 8 static int args[MAXARGS], argc; static int fg_c, bg_c, curx, cury; static int esc; void get_pos(int *x, int *y); void curs_move(int *_x, int *_y, int x, int y); static void CL(int); void HO(void); void end_term(void); #endif +static EFI_INPUT_KEY key_cur; +static int key_pending; + static void efi_cons_probe(struct console *); static int efi_cons_init(int); void efi_cons_putchar(int); int efi_cons_getchar(void); void efi_cons_efiputchar(int); int efi_cons_poll(void); struct console efi_console = { "efi", "EFI console", C_WIDEOUT, efi_cons_probe, efi_cons_init, efi_cons_putchar, efi_cons_getchar, efi_cons_poll }; #ifdef TERM_EMU /* Get cursor position. */ void get_pos(int *x, int *y) { *x = conout->Mode->CursorColumn; *y = conout->Mode->CursorRow; } /* Move cursor to x rows and y cols (0-based). */ void curs_move(int *_x, int *_y, int x, int y) { conout->SetCursorPosition(conout, x, y); if (_x != NULL) *_x = conout->Mode->CursorColumn; if (_y != NULL) *_y = conout->Mode->CursorRow; } /* Clear internal state of the terminal emulation code. */ void end_term(void) { esc = 0; argc = -1; } #endif static void efi_cons_probe(struct console *cp) { conout = ST->ConOut; conin = ST->ConIn; cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; } static int efi_cons_init(int arg) { #ifdef TERM_EMU conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, DEFAULT_BGCOLOR)); end_term(); get_pos(&curx, &cury); curs_move(&curx, &cury, curx, cury); fg_c = DEFAULT_FGCOLOR; bg_c = DEFAULT_BGCOLOR; #endif conout->EnableCursor(conout, TRUE); return 0; } static void efi_cons_rawputchar(int c) { int i; UINTN x, y; conout->QueryMode(conout, conout->Mode->Mode, &x, &y); if (c == '\t') /* XXX lame tab expansion */ for (i = 0; i < 8; i++) efi_cons_rawputchar(' '); else { #ifndef TERM_EMU if (c == '\n') efi_cons_efiputchar('\r'); efi_cons_efiputchar(c); #else switch (c) { case '\r': curx = 0; curs_move(&curx, &cury, curx, cury); return; case '\n': cury++; if (cury >= y) { efi_cons_efiputchar('\n'); cury--; } else curs_move(&curx, &cury, curx, cury); return; case '\b': if (curx > 0) { curx--; curs_move(&curx, &cury, curx, cury); } return; default: efi_cons_efiputchar(c); curx++; if (curx > x-1) { curx = 0; cury++; } if (cury > y-1) { curx = 0; cury--; } } curs_move(&curx, &cury, curx, cury); #endif } } #ifdef TERM_EMU /* Gracefully exit ESC-sequence processing in case of misunderstanding. */ static void bail_out(int c) { char buf[16], *ch; int i; if (esc) { efi_cons_rawputchar('\033'); if (esc != '\033') efi_cons_rawputchar(esc); for (i = 0; i <= argc; ++i) { sprintf(buf, "%d", args[i]); ch = buf; while (*ch) efi_cons_rawputchar(*ch++); } } efi_cons_rawputchar(c); end_term(); } /* Clear display from current position to end of screen. */ static void CD(void) { int i; UINTN x, y; get_pos(&curx, &cury); if (curx == 0 && cury == 0) { conout->ClearScreen(conout); end_term(); return; } conout->QueryMode(conout, conout->Mode->Mode, &x, &y); CL(0); /* clear current line from cursor to end */ for (i = cury + 1; i < y-1; i++) { curs_move(NULL, NULL, 0, i); CL(0); } curs_move(NULL, NULL, curx, cury); end_term(); } /* * Absolute cursor move to args[0] rows and args[1] columns * (the coordinates are 1-based). */ static void CM(void) { if (args[0] > 0) args[0]--; if (args[1] > 0) args[1]--; curs_move(&curx, &cury, args[1], args[0]); end_term(); } /* Home cursor (left top corner), also called from mode command. */ void HO(void) { argc = 1; args[0] = args[1] = 1; CM(); } /* Clear line from current position to end of line */ static void CL(int direction) { int i, len; UINTN x, y; CHAR16 *line; conout->QueryMode(conout, conout->Mode->Mode, &x, &y); switch (direction) { case 0: /* from cursor to end */ len = x - curx + 1; break; case 1: /* from beginning to cursor */ len = curx; break; case 2: /* entire line */ len = x; break; default: /* NOTREACHED */ __unreachable(); } if (cury == y - 1) len--; line = malloc(len * sizeof (CHAR16)); if (line == NULL) { printf("out of memory\n"); return; } for (i = 0; i < len; i++) line[i] = ' '; line[len-1] = 0; if (direction != 0) curs_move(NULL, NULL, 0, cury); conout->OutputString(conout, line); /* restore cursor position */ curs_move(NULL, NULL, curx, cury); free(line); end_term(); } static void get_arg(int c) { if (argc < 0) argc = 0; args[argc] *= 10; args[argc] += c - '0'; } /* Emulate basic capabilities of cons25 terminal */ static void efi_term_emu(int c) { static int ansi_col[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; int t, i; switch (esc) { case 0: switch (c) { case '\033': esc = c; break; default: efi_cons_rawputchar(c); break; } break; case '\033': switch (c) { case '[': esc = c; args[0] = 0; argc = -1; break; default: bail_out(c); break; } break; case '[': switch (c) { case ';': if (argc < 0) argc = 0; else if (argc + 1 >= MAXARGS) bail_out(c); else args[++argc] = 0; break; case 'H': /* ho = \E[H */ if (argc < 0) HO(); else if (argc == 1) CM(); else bail_out(c); break; case 'J': /* cd = \E[J */ if (argc < 0) CD(); else bail_out(c); break; case 'm': if (argc < 0) { fg_c = DEFAULT_FGCOLOR; bg_c = DEFAULT_BGCOLOR; } for (i = 0; i <= argc; ++i) { switch (args[i]) { case 0: /* back to normal */ fg_c = DEFAULT_FGCOLOR; bg_c = DEFAULT_BGCOLOR; break; case 1: /* bold */ fg_c |= 0x8; break; case 4: /* underline */ case 5: /* blink */ bg_c |= 0x8; break; case 7: /* reverse */ t = fg_c; fg_c = bg_c; bg_c = t; break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: fg_c = ansi_col[args[i] - 30]; break; case 39: /* normal */ fg_c = DEFAULT_FGCOLOR; break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: bg_c = ansi_col[args[i] - 40]; break; case 49: /* normal */ bg_c = DEFAULT_BGCOLOR; break; } } conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); end_term(); break; default: if (isdigit(c)) get_arg(c); else bail_out(c); break; } break; default: bail_out(c); break; } } #else void HO(void) { } #endif void efi_cons_putchar(int c) { #ifdef TERM_EMU efi_term_emu(c); #else efi_cons_rawputchar(c); #endif } int efi_cons_getchar() { EFI_INPUT_KEY key; EFI_STATUS status; UINTN junk; - /* Try to read a key stroke. We wait for one if none is pending. */ - status = conin->ReadKeyStroke(conin, &key); - while (status == EFI_NOT_READY) { - /* Some EFI implementation (u-boot for example) do not support WaitForKey */ - if (conin->WaitForKey != NULL) - BS->WaitForEvent(1, &conin->WaitForKey, &junk); + if (key_pending) { + key = key_cur; + key_pending = 0; + } else { + /* Try to read a key stroke. We wait for one if none is pending. */ status = conin->ReadKeyStroke(conin, &key); + while (status == EFI_NOT_READY) { + /* Some EFI implementation (u-boot for example) do not support WaitForKey */ + if (conin->WaitForKey != NULL) + BS->WaitForEvent(1, &conin->WaitForKey, &junk); + status = conin->ReadKeyStroke(conin, &key); + } } + switch (key.ScanCode) { case 0x17: /* ESC */ return (0x1b); /* esc */ } /* this can return */ return (key.UnicodeChar); } int efi_cons_poll() { + EFI_INPUT_KEY key; + EFI_STATUS status; - if (conin->WaitForKey == NULL) - return (1); + if (conin->WaitForKey == NULL) { + if (key_pending) + return (1); + status = conin->ReadKeyStroke(conin, &key); + if (status == EFI_SUCCESS) { + key_cur = key; + key_pending = 1; + } + return (key_pending); + } + /* This can clear the signaled state. */ return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); } /* Plain direct access to EFI OutputString(). */ void efi_cons_efiputchar(int c) { CHAR16 buf[2]; /* * translate box chars to unicode */ switch (c) { /* single frame */ case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; /* double frame */ case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; default: buf[0] = c; } buf[1] = 0; /* terminate string */ conout->OutputString(conout, buf); } Index: stable/11/sys/boot/efi/libefi/time.c =================================================================== --- stable/11/sys/boot/efi/libefi/time.c (revision 329009) +++ stable/11/sys/boot/efi/libefi/time.c (revision 329010) @@ -1,234 +1,234 @@ /*- * Copyright (c) 1999, 2000 * Intel Corporation. * 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. * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Intel Corporation and * its contributors. * * 4. Neither the name of Intel Corporation or its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION 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 INTEL CORPORATION 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 /* // Accurate only for the past couple of centuries; // that will probably do. // // (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h) */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #define SECSPERHOUR ( 60*60 ) #define SECSPERDAY (24 * SECSPERHOUR) void efi_time_init(void) { } void efi_time_fini(void) { } static time_t efi_time(EFI_TIME *ETime) { /* // These arrays give the cumulative number of days up to the first of the // month number used as the index (1 -> 12) for regular and leap years. // The value at index 13 is for the whole year. */ static time_t CumulativeDays[2][14] = { {0, 0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, {0, 0, 31, 31 + 29, 31 + 29 + 31, 31 + 29 + 31 + 30, 31 + 29 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; time_t UTime; int Year; /* // Do a santity check */ if ( ETime->Year < 1998 || ETime->Year > 2099 || ETime->Month == 0 || ETime->Month > 12 || ETime->Day == 0 || ETime->Month > 31 || ETime->Hour > 23 || ETime->Minute > 59 || ETime->Second > 59 || ETime->TimeZone < -1440 || (ETime->TimeZone > 1440 && ETime->TimeZone != 2047) ) { return (0); } /* // Years */ UTime = 0; for (Year = 1970; Year != ETime->Year; ++Year) { UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY); } /* // UTime should now be set to 00:00:00 on Jan 1 of the file's year. // // Months */ UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * SECSPERDAY); /* // UTime should now be set to 00:00:00 on the first of the file's month and year // // Days -- Don't count the file's day */ UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY); /* // Hours */ UTime += (ETime->Hour * SECSPERHOUR); /* // Minutes */ UTime += (ETime->Minute * 60); /* // Seconds */ UTime += ETime->Second; /* // EFI time is repored in local time. Adjust for any time zone offset to // get true UT */ if ( ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE ) { /* // TimeZone is kept in minues... */ UTime += (ETime->TimeZone * 60); } return UTime; } static int EFI_GetTimeOfDay( OUT struct timeval *tp, OUT struct timezone *tzp ) { EFI_TIME EfiTime; EFI_TIME_CAPABILITIES Capabilities; EFI_STATUS Status; /* // Get time from EFI */ Status = RS->GetTime(&EfiTime, &Capabilities); if (EFI_ERROR(Status)) return (-1); /* // Convert to UNIX time (ie seconds since the epoch */ tp->tv_sec = efi_time( &EfiTime ); tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ /* // Do something with the timezone if needed */ if (tzp) { tzp->tz_minuteswest = EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE ? 0 : EfiTime.TimeZone; /* // This isn't quit right since it doesn't deal with EFI_TIME_IN_DAYLIGHT */ tzp->tz_dsttime = EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0; } return (0); } time_t time(time_t *tloc) { struct timeval tv; EFI_GetTimeOfDay(&tv, 0); if (tloc) *tloc = tv.tv_sec; return tv.tv_sec; } time_t -getsecs() +getsecs(void) { return time(0); } Index: stable/11/sys/boot/efi/libefi/time_event.c =================================================================== --- stable/11/sys/boot/efi/libefi/time_event.c (revision 329009) +++ stable/11/sys/boot/efi/libefi/time_event.c (revision 329010) @@ -1,82 +1,82 @@ /*- * Copyright (c) 2016 Andrew Turner * 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 static EFI_EVENT time_event; static uint64_t curtime; static void time_update(EFI_EVENT event, void *context) { curtime += 10; } void efi_time_init(void) { /* Create a timer event */ BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, time_update, 0, &time_event); /* Use a 10ms timer */ BS->SetTimer(time_event, TimerPeriodic, 100000); } void efi_time_fini(void) { /* Cancel the timer */ BS->SetTimer(time_event, TimerCancel, 0); BS->CloseEvent(time_event); } time_t time(time_t *tloc) { time_t t; t = curtime / 1000; if (tloc != NULL) *tloc = t; return (t); } time_t -getsecs() +getsecs(void) { return time(0); } Index: stable/11/sys/boot/efi/loader/arch/amd64/framebuffer.c =================================================================== --- stable/11/sys/boot/efi/loader/arch/amd64/framebuffer.c (revision 329009) +++ stable/11/sys/boot/efi/loader/arch/amd64/framebuffer.c (revision 329010) @@ -1,566 +1,568 @@ /*- * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * * This software was developed by Benno Rice 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 #include #include "framebuffer.h" static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; static u_int efifb_color_depth(struct efi_fb *efifb) { uint32_t mask; u_int depth; mask = efifb->fb_mask_red | efifb->fb_mask_green | efifb->fb_mask_blue | efifb->fb_mask_reserved; if (mask == 0) return (0); for (depth = 1; mask != 1; depth++) mask >>= 1; return (depth); } static int efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, EFI_PIXEL_BITMASK *pixinfo) { int result; result = 0; switch (pixfmt) { case PixelRedGreenBlueReserved8BitPerColor: efifb->fb_mask_red = 0x000000ff; efifb->fb_mask_green = 0x0000ff00; efifb->fb_mask_blue = 0x00ff0000; efifb->fb_mask_reserved = 0xff000000; break; case PixelBlueGreenRedReserved8BitPerColor: efifb->fb_mask_red = 0x00ff0000; efifb->fb_mask_green = 0x0000ff00; efifb->fb_mask_blue = 0x000000ff; efifb->fb_mask_reserved = 0xff000000; break; case PixelBitMask: efifb->fb_mask_red = pixinfo->RedMask; efifb->fb_mask_green = pixinfo->GreenMask; efifb->fb_mask_blue = pixinfo->BlueMask; efifb->fb_mask_reserved = pixinfo->ReservedMask; break; default: result = 1; break; } return (result); } static int efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) { int result; efifb->fb_addr = mode->FrameBufferBase; efifb->fb_size = mode->FrameBufferSize; efifb->fb_height = info->VerticalResolution; efifb->fb_width = info->HorizontalResolution; efifb->fb_stride = info->PixelsPerScanLine; result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, &info->PixelInformation); return (result); } static ssize_t efifb_uga_find_pixel(EFI_UGA_DRAW_PROTOCOL *uga, u_int line, EFI_PCI_IO_PROTOCOL *pciio, uint64_t addr, uint64_t size) { EFI_UGA_PIXEL pix0, pix1; uint8_t *data1, *data2; size_t count, maxcount = 1024; ssize_t ofs; EFI_STATUS status; u_int idx; status = uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, 0, line, 0, 0, 1, 1, 0); if (EFI_ERROR(status)) { printf("UGA BLT operation failed (video->buffer)"); return (-1); } pix1.Red = ~pix0.Red; pix1.Green = ~pix0.Green; pix1.Blue = ~pix0.Blue; pix1.Reserved = 0; data1 = calloc(maxcount, 2); if (data1 == NULL) { printf("Unable to allocate memory"); return (-1); } data2 = data1 + maxcount; ofs = 0; while (size > 0) { count = min(size, maxcount); status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, data1); if (EFI_ERROR(status)) { printf("Error reading frame buffer (before)"); goto fail; } status = uga->Blt(uga, &pix1, EfiUgaBltBufferToVideo, 0, 0, 0, line, 1, 1, 0); if (EFI_ERROR(status)) { printf("UGA BLT operation failed (modify)"); goto fail; } status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, data2); if (EFI_ERROR(status)) { printf("Error reading frame buffer (after)"); goto fail; } status = uga->Blt(uga, &pix0, EfiUgaBltBufferToVideo, 0, 0, 0, line, 1, 1, 0); if (EFI_ERROR(status)) { printf("UGA BLT operation failed (restore)"); goto fail; } for (idx = 0; idx < count; idx++) { if (data1[idx] != data2[idx]) { free(data1); return (ofs + (idx & ~3)); } } ofs += count; size -= count; } printf("No change detected in frame buffer"); fail: printf(" -- error %lu\n", EFI_ERROR_CODE(status)); free(data1); return (-1); } static EFI_PCI_IO_PROTOCOL * efifb_uga_get_pciio(void) { EFI_PCI_IO_PROTOCOL *pciio; EFI_HANDLE *buf, *hp; EFI_STATUS status; UINTN bufsz; /* Get all handles that support the UGA protocol. */ bufsz = 0; status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, NULL); if (status != EFI_BUFFER_TOO_SMALL) return (NULL); buf = malloc(bufsz); status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, buf); if (status != EFI_SUCCESS) { free(buf); return (NULL); } bufsz /= sizeof(EFI_HANDLE); /* Get the PCI I/O interface of the first handle that supports it. */ pciio = NULL; for (hp = buf; hp < buf + bufsz; hp++) { status = BS->HandleProtocol(*hp, &pciio_guid, (void **)&pciio); if (status == EFI_SUCCESS) { free(buf); return (pciio); } } free(buf); return (NULL); } static EFI_STATUS efifb_uga_locate_framebuffer(EFI_PCI_IO_PROTOCOL *pciio, uint64_t *addrp, uint64_t *sizep) { uint8_t *resattr; uint64_t addr, size; EFI_STATUS status; u_int bar; if (pciio == NULL) return (EFI_DEVICE_ERROR); /* Attempt to get the frame buffer address (imprecise). */ *addrp = 0; *sizep = 0; for (bar = 0; bar < 6; bar++) { status = pciio->GetBarAttributes(pciio, bar, NULL, (void **)&resattr); if (status != EFI_SUCCESS) continue; /* XXX magic offsets and constants. */ if (resattr[0] == 0x87 && resattr[3] == 0) { /* 32-bit address space descriptor (MEMIO) */ addr = le32dec(resattr + 10); size = le32dec(resattr + 22); } else if (resattr[0] == 0x8a && resattr[3] == 0) { /* 64-bit address space descriptor (MEMIO) */ addr = le64dec(resattr + 14); size = le64dec(resattr + 38); } else { addr = 0; size = 0; } BS->FreePool(resattr); if (addr == 0 || size == 0) continue; /* We assume the largest BAR is the frame buffer. */ if (size > *sizep) { *addrp = addr; *sizep = size; } } return ((*addrp == 0 || *sizep == 0) ? EFI_DEVICE_ERROR : 0); } static int efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) { EFI_PCI_IO_PROTOCOL *pciio; char *ev, *p; EFI_STATUS status; ssize_t offset; uint64_t fbaddr; uint32_t horiz, vert, stride; uint32_t np, depth, refresh; status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); if (EFI_ERROR(status)) return (1); efifb->fb_height = vert; efifb->fb_width = horiz; /* Paranoia... */ if (efifb->fb_height == 0 || efifb->fb_width == 0) return (1); /* The color masks are fixed AFAICT. */ efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, NULL); /* pciio can be NULL on return! */ pciio = efifb_uga_get_pciio(); /* Try to find the frame buffer. */ status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, &efifb->fb_size); if (EFI_ERROR(status)) { efifb->fb_addr = 0; efifb->fb_size = 0; } /* * There's no reliable way to detect the frame buffer or the * offset within the frame buffer of the visible region, nor * the stride. Our only option is to look at the system and * fill in the blanks based on that. Luckily, UGA was mostly * only used on Apple hardware. */ offset = -1; ev = getenv("smbios.system.maker"); if (ev != NULL && !strcmp(ev, "Apple Inc.")) { ev = getenv("smbios.system.product"); if (ev != NULL && !strcmp(ev, "iMac7,1")) { /* These are the expected values we should have. */ horiz = 1680; vert = 1050; fbaddr = 0xc0000000; /* These are the missing bits. */ offset = 0x10000; stride = 1728; } else if (ev != NULL && !strcmp(ev, "MacBook3,1")) { /* These are the expected values we should have. */ horiz = 1280; vert = 800; fbaddr = 0xc0000000; /* These are the missing bits. */ offset = 0x0; stride = 2048; } } /* * If this is hardware we know, make sure that it looks familiar * before we accept our hardcoded values. */ if (offset >= 0 && efifb->fb_width == horiz && efifb->fb_height == vert && efifb->fb_addr == fbaddr) { efifb->fb_addr += offset; efifb->fb_size -= offset; efifb->fb_stride = stride; return (0); } else if (offset >= 0) { printf("Hardware make/model known, but graphics not " "as expected.\n"); printf("Console may not work!\n"); } /* * The stride is equal or larger to the width. Often it's the * next larger power of two. We'll start with that... */ efifb->fb_stride = efifb->fb_width; do { np = efifb->fb_stride & (efifb->fb_stride - 1); if (np) { efifb->fb_stride |= (np - 1); efifb->fb_stride++; } } while (np); ev = getenv("hw.efifb.address"); if (ev == NULL) { if (efifb->fb_addr == 0) { printf("Please set hw.efifb.address and " "hw.efifb.stride.\n"); return (1); } /* * The visible part of the frame buffer may not start at * offset 0, so try to detect it. Note that we may not * always be able to read from the frame buffer, which * means that we may not be able to detect anything. In * that case, we would take a long time scanning for a * pixel change in the frame buffer, which would have it * appear that we're hanging, so we limit the scan to * 1/256th of the frame buffer. This number is mostly * based on PR 202730 and the fact that on a MacBoook, * where we can't read from the frame buffer the offset * of the visible region is 0. In short: we want to scan * enough to handle all adapters that have an offset * larger than 0 and we want to scan as little as we can * to not appear to hang when we can't read from the * frame buffer. */ offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, efifb->fb_size >> 8); if (offset == -1) { printf("Unable to reliably detect frame buffer.\n"); } else if (offset > 0) { efifb->fb_addr += offset; efifb->fb_size -= offset; } } else { offset = 0; efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; efifb->fb_addr = strtoul(ev, &p, 0); if (*p != '\0') return (1); } ev = getenv("hw.efifb.stride"); if (ev == NULL) { if (pciio != NULL && offset != -1) { /* Determine the stride. */ offset = efifb_uga_find_pixel(uga, 1, pciio, efifb->fb_addr, horiz * 8); if (offset != -1) efifb->fb_stride = offset >> 2; } else { printf("Unable to reliably detect the stride.\n"); } } else { efifb->fb_stride = strtoul(ev, &p, 0); if (*p != '\0') return (1); } /* * We finalized on the stride, so recalculate the size of the * frame buffer. */ efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; return (0); } int efi_find_framebuffer(struct efi_fb *efifb) { EFI_GRAPHICS_OUTPUT *gop; EFI_UGA_DRAW_PROTOCOL *uga; EFI_STATUS status; status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); if (status == EFI_SUCCESS) return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); if (status == EFI_SUCCESS) return (efifb_from_uga(efifb, uga)); return (1); } static void print_efifb(int mode, struct efi_fb *efifb, int verbose) { u_int depth; if (mode >= 0) printf("mode %d: ", mode); depth = efifb_color_depth(efifb); printf("%ux%ux%u, stride=%u", efifb->fb_width, efifb->fb_height, depth, efifb->fb_stride); if (verbose) { printf("\n frame buffer: address=%jx, size=%jx", (uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size); printf("\n color mask: R=%08x, G=%08x, B=%08x\n", efifb->fb_mask_red, efifb->fb_mask_green, efifb->fb_mask_blue); } } COMMAND_SET(gop, "gop", "graphics output protocol", command_gop); static int command_gop(int argc, char *argv[]) { struct efi_fb efifb; EFI_GRAPHICS_OUTPUT *gop; EFI_STATUS status; u_int mode; status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); if (EFI_ERROR(status)) { - sprintf(command_errbuf, "%s: Graphics Output Protocol not " - "present (error=%lu)", argv[0], EFI_ERROR_CODE(status)); + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Graphics Output Protocol not present (error=%lu)", + argv[0], EFI_ERROR_CODE(status)); return (CMD_ERROR); } if (argc < 2) goto usage; if (!strcmp(argv[1], "set")) { char *cp; if (argc != 3) goto usage; mode = strtol(argv[2], &cp, 0); if (cp[0] != '\0') { sprintf(command_errbuf, "mode is an integer"); return (CMD_ERROR); } status = gop->SetMode(gop, mode); if (EFI_ERROR(status)) { - sprintf(command_errbuf, "%s: Unable to set mode to " - "%u (error=%lu)", argv[0], mode, - EFI_ERROR_CODE(status)); + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Unable to set mode to %u (error=%lu)", + argv[0], mode, EFI_ERROR_CODE(status)); return (CMD_ERROR); } } else if (!strcmp(argv[1], "get")) { if (argc != 2) goto usage; efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info); print_efifb(gop->Mode->Mode, &efifb, 1); printf("\n"); } else if (!strcmp(argv[1], "list")) { EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; UINTN infosz; if (argc != 2) goto usage; pager_open(); for (mode = 0; mode < gop->Mode->MaxMode; mode++) { status = gop->QueryMode(gop, mode, &infosz, &info); if (EFI_ERROR(status)) continue; efifb_from_gop(&efifb, gop->Mode, info); print_efifb(mode, &efifb, 0); if (pager_output("\n")) break; } pager_close(); } return (CMD_OK); usage: - sprintf(command_errbuf, "usage: %s [list | get | set ]", - argv[0]); + snprintf(command_errbuf, sizeof(command_errbuf), + "usage: %s [list | get | set ]", argv[0]); return (CMD_ERROR); } COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga); static int command_uga(int argc, char *argv[]) { struct efi_fb efifb; EFI_UGA_DRAW_PROTOCOL *uga; EFI_STATUS status; status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); if (EFI_ERROR(status)) { - sprintf(command_errbuf, "%s: UGA Protocol not present " - "(error=%lu)", argv[0], EFI_ERROR_CODE(status)); + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: UGA Protocol not present (error=%lu)", + argv[0], EFI_ERROR_CODE(status)); return (CMD_ERROR); } if (argc != 1) goto usage; if (efifb_from_uga(&efifb, uga) != CMD_OK) { - sprintf(command_errbuf, "%s: Unable to get UGA information", - argv[0]); + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Unable to get UGA information", argv[0]); return (CMD_ERROR); } print_efifb(-1, &efifb, 1); printf("\n"); return (CMD_OK); usage: - sprintf(command_errbuf, "usage: %s", argv[0]); + snprintf(command_errbuf, sizeof(command_errbuf), "usage: %s", argv[0]); return (CMD_ERROR); } Index: stable/11/sys/boot/efi/loader/main.c =================================================================== --- stable/11/sys/boot/efi/loader/main.c (revision 329009) +++ stable/11/sys/boot/efi/loader/main.c (revision 329010) @@ -1,1058 +1,1084 @@ /*- * 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 #ifdef EFI_ZFS_BOOT #include #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 dxe = DXE_SERVICES_TABLE_GUID; EFI_GUID hoblist = HOB_LIST_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; #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void); #endif /* * cpy8to16 copies a traditional C string into a CHAR16 string and * 0 terminates it. len is the size of *dst in bytes. */ static void cpy8to16(const char *src, CHAR16 *dst, size_t len) { len <<= 1; /* Assume CHAR16 is 2 bytes */ while (len > 0 && *src) { *dst++ = *src++; len--; } *dst++ = (CHAR16)0; } static void cpy16to8(const CHAR16 *src, char *dst, size_t len) { size_t i; for (i = 0; i < len && src[i]; i++) dst[i] = (char)src[i]; if (i < len) dst[i] = '\0'; } 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 int find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, uint64_t *extra) { EFI_DEVICE_PATH *devpath, *copy; EFI_HANDLE h; /* * 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. */ if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0) return (0); copy = NULL; devpath = efi_lookup_image_devpath(IH); while (devpath != NULL) { h = efi_devpath_handle(devpath); if (h == NULL) break; if (efi_handle_lookup(h, dev, unit, extra) == 0) { if (copy != NULL) free(copy); return (0); } if (copy != NULL) free(copy); devpath = efi_lookup_devpath(h); if (devpath != NULL) { copy = efi_devpath_trim(devpath); devpath = copy; } } return (ENOENT); } EFI_STATUS main(int argc, CHAR16 *argv[]) { char var[128]; EFI_LOADED_IMAGE *img; EFI_GUID *guid; int i, j, vargood, unit, howto; struct devsw *dev; uint64_t pool_guid; UINTN k; int has_kbd; 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 /* 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. * * 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. */ 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 = 0; for (j = 0; argv[i][j] != 0; j++) { if (j == sizeof(var)) { vargood = 0; break; } if (j > 0 && argv[i][j] == '=') vargood = 1; var[j] = (char)argv[i][j]; } if (vargood) { var[j] = 0; putenv(var); } } } for (i = 0; howto_names[i].ev != NULL; i++) if (howto & howto_names[i].mask) setenv(howto_names[i].ev, "YES", 1); 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); } if (efi_copy_init()) { printf("failed to allocate staging area\n"); return (EFI_BUFFER_TOO_SMALL); } /* * 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)(); /* Get our loaded image protocol interface structure. */ BS->HandleProtocol(IH, &imgid, (VOID**)&img); 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); /* * 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); if (find_currdev(img, &dev, &unit, &pool_guid) != 0) return (EFI_NOT_FOUND); switch (dev->dv_type) { #ifdef EFI_ZFS_BOOT case DEVT_ZFS: { struct zfs_devdesc currdev; currdev.d_dev = dev; currdev.d_unit = unit; currdev.d_type = currdev.d_dev->dv_type; currdev.d_opendata = NULL; currdev.pool_guid = pool_guid; currdev.root_guid = 0; env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), efi_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, env_nounset); init_zfs_bootenv(zfs_fmtdev(&currdev)); break; } #endif default: { struct devdesc currdev; currdev.d_dev = dev; currdev.d_unit = unit; currdev.d_opendata = NULL; currdev.d_type = currdev.d_dev->dv_type; env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), efi_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, env_nounset); break; } } snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ for (k = 0; k < ST->NumberOfTableEntries; k++) { guid = &ST->ConfigurationTable[k].VendorGuid; if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { smbios_detect(ST->ConfigurationTable[k].VendorTable); break; } } interact(NULL); /* doesn't return */ return (EFI_SUCCESS); /* keep compiler happy */ } /* XXX move to lib stand ? */ static int wcscmp(CHAR16 *a, CHAR16 *b) { while (*a && *b && *a == *b) { a++; b++; } return *a - *b; } 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, 23, (CHAR16 *)"Reboot from the loader"); /* 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"); 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, &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 EFI_ZFS_BOOT COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", command_lszfs); static int command_lszfs(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } err = zfs_list(argv[1]); if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", command_reloadbe); static int command_reloadbe(int argc, char *argv[]) { int err; char *root; if (argc > 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } if (argc == 2) { err = zfs_bootenv(argv[1]); } else { root = getenv("zfs_be_root"); if (root == NULL) { return (CMD_OK); } err = zfs_bootenv(root); } if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } #endif COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); static int efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) { UINTN datasz, i; EFI_STATUS status; UINT32 attr; CHAR16 *data; char *str; uint32_t uuid_status; int is_ascii; datasz = 0; status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { printf("Can't get the variable: error %#lx\n", status); return (CMD_ERROR); } data = malloc(datasz); status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data); if (status != EFI_SUCCESS) { printf("Can't get the variable: error %#lx\n", status); return (CMD_ERROR); } uuid_to_string((uuid_t *)matchguid, &str, &uuid_status); if (lflag) { printf("%s 0x%x %S", str, attr, varnamearg); } else { printf("%s 0x%x %S=", str, attr, varnamearg); is_ascii = 1; free(str); str = (char *)data; for (i = 0; i < datasz - 1; i++) { /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */ if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) { is_ascii = 0; break; } } if (str[datasz - 1] != '\0') is_ascii = 0; if (is_ascii) printf("%s", str); else { for (i = 0; i < datasz / 2; i++) { if (isalnum(data[i]) || isspace(data[i])) printf("%c", data[i]); else printf("\\x%02x", data[i]); } } } free(data); if (pager_output("\n")) return (CMD_WARN); return (CMD_OK); } static int command_efi_show(int argc, char *argv[]) { /* * efi-show [-a] * print all the env * efi-show -u UUID * print all the env vars tagged with UUID * efi-show -v var * search all the env vars and print the ones matching var * eif-show -u UUID -v var * eif-show UUID var * print all the env vars that match UUID and var */ /* NB: We assume EFI_GUID is the same as uuid_t */ int aflag = 0, gflag = 0, lflag = 0, vflag = 0; int ch, rv; unsigned i; EFI_STATUS status; EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; uint32_t uuid_status; - CHAR16 varname[128]; + CHAR16 *varname; + CHAR16 *newnm; CHAR16 varnamearg[128]; + UINTN varalloc; UINTN varsz; while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { switch (ch) { case 'a': aflag = 1; break; case 'g': gflag = 1; uuid_from_string(optarg, (uuid_t *)&matchguid, &uuid_status); if (uuid_status != uuid_s_ok) { printf("uid %s could not be parsed\n", optarg); return (CMD_ERROR); } break; case 'l': lflag = 1; break; case 'v': vflag = 1; if (strlen(optarg) >= nitems(varnamearg)) { printf("Variable %s is longer than %zd characters\n", optarg, nitems(varnamearg)); return (CMD_ERROR); } for (i = 0; i < strlen(optarg); i++) varnamearg[i] = optarg[i]; varnamearg[i] = 0; break; default: printf("Invalid argument %c\n", ch); return (CMD_ERROR); } } if (aflag && (gflag || vflag)) { printf("-a isn't compatible with -v or -u\n"); return (CMD_ERROR); } if (aflag && optind < argc) { printf("-a doesn't take any args"); return (CMD_ERROR); } if (optind == argc) aflag = 1; argc -= optind; argv += optind; pager_open(); if (vflag && gflag) { rv = efi_print_var(varnamearg, &matchguid, lflag); pager_close(); return (rv); } if (argc == 2) { optarg = argv[0]; if (strlen(optarg) >= nitems(varnamearg)) { printf("Variable %s is longer than %zd characters\n", optarg, nitems(varnamearg)); pager_close(); return (CMD_ERROR); } for (i = 0; i < strlen(optarg); i++) varnamearg[i] = optarg[i]; varnamearg[i] = 0; optarg = argv[1]; uuid_from_string(optarg, (uuid_t *)&matchguid, &uuid_status); if (uuid_status != uuid_s_ok) { printf("uid %s could not be parsed\n", optarg); pager_close(); return (CMD_ERROR); } rv = efi_print_var(varnamearg, &matchguid, lflag); pager_close(); return (rv); } if (argc != 0) { printf("Too many args\n"); pager_close(); return (CMD_ERROR); } /* * Initiate the search -- note the standard takes pain * to specify the initial call must be a poiner to a NULL * character. */ - varsz = nitems(varname); + varalloc = 1024; + varname = malloc(varalloc); + if (varname == NULL) { + printf("Can't allocate memory to get variables\n"); + pager_close(); + return (CMD_ERROR); + } varname[0] = 0; - while ((status = RS->GetNextVariableName(&varsz, varname, &varguid)) != - EFI_NOT_FOUND) { + while (1) { + varsz = varalloc; + status = RS->GetNextVariableName(&varsz, varname, &varguid); + if (status == EFI_BUFFER_TOO_SMALL) { + varalloc = varsz; + newnm = malloc(varalloc); + if (newnm == NULL) { + printf("Can't allocate memory to get variables\n"); + free(varname); + pager_close(); + return (CMD_ERROR); + } + memcpy(newnm, varname, varsz); + free(varname); + varname = newnm; + continue; /* Try again with bigger buffer */ + } + if (status != EFI_SUCCESS) + break; if (aflag) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } if (vflag) { if (wcscmp(varnamearg, varname) == 0) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } } if (gflag) { if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; } } } + free(varname); pager_close(); return (CMD_OK); } COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); static int command_efi_set(int argc, char *argv[]) { char *uuid, *var, *val; CHAR16 wvar[128]; EFI_GUID guid; uint32_t status; EFI_STATUS err; if (argc != 4) { printf("efi-set uuid var new-value\n"); return (CMD_ERROR); } uuid = argv[1]; var = argv[2]; val = argv[3]; uuid_from_string(uuid, (uuid_t *)&guid, &status); if (status != uuid_s_ok) { printf("Invalid uuid %s %d\n", uuid, status); return (CMD_ERROR); } cpy8to16(var, wvar, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, strlen(val) + 1, val); if (EFI_ERROR(err)) { printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err)); return (CMD_ERROR); } return (CMD_OK); } COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); static int command_efi_unset(int argc, char *argv[]) { char *uuid, *var; CHAR16 wvar[128]; EFI_GUID guid; uint32_t status; EFI_STATUS err; if (argc != 3) { printf("efi-unset uuid var\n"); return (CMD_ERROR); } uuid = argv[1]; var = argv[2]; uuid_from_string(uuid, (uuid_t *)&guid, &status); if (status != uuid_s_ok) { printf("Invalid uuid %s\n", uuid); return (CMD_ERROR); } cpy8to16(var, wvar, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, 0, 0, NULL); if (EFI_ERROR(err)) { printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); return (CMD_ERROR); } 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 #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void) { EFI_HANDLE h; u_int unit; int i; char dname[SPECNAMELEN + 1]; uint64_t guid; unit = 0; h = efi_find_handle(&efipart_dev, 0); for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); if (zfs_probe_dev(dname, &guid) == 0) (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); } } #endif Index: stable/11/sys/boot/fdt/fdt_loader_cmd.c =================================================================== --- stable/11/sys/boot/fdt/fdt_loader_cmd.c (revision 329009) +++ stable/11/sys/boot/fdt/fdt_loader_cmd.c (revision 329010) @@ -1,1787 +1,1796 @@ /*- * 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 12 #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 void fdt_print_overlay_load_error(int err, const char *filename); static int fdt_cmd_nyi(int argc, char *argv[]); static int fdt_load_dtb_overlays_string(const char * filenames); 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 efficient 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, + if (err == -FDT_ERR_BADVERSION) { + snprintf(command_errbuf, sizeof(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)); + } else { + snprintf(command_errbuf, sizeof(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)); + snprintf(command_errbuf, sizeof(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); + snprintf(command_errbuf, sizeof(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); } static int fdt_load_dtb_overlay(const char * filename) { struct preloaded_file *bfp; struct fdt_header header; int err; debugf("fdt_load_dtb_overlay(%s)\n", filename); /* Attempt to load and validate a new dtb from a file. FDT_ERR_NOTFOUND * is normally a libfdt error code, but libfdt would actually return * -FDT_ERR_NOTFOUND. We re-purpose the error code here to convey a * similar meaning: the file itself was not found, which can still be * considered an error dealing with FDT pieces. */ if ((bfp = file_loadraw(filename, "dtbo", 1)) == NULL) return (FDT_ERR_NOTFOUND); COPYOUT(bfp->f_addr, &header, sizeof(header)); err = fdt_check_header(&header); if (err < 0) { file_discard(bfp); return (err); } return (0); } static void fdt_print_overlay_load_error(int err, const char *filename) { switch (err) { case FDT_ERR_NOTFOUND: printf("%s: failed to load file\n", filename); break; case -FDT_ERR_BADVERSION: printf("%s: incompatible blob version: %d, should be: %d\n", filename, fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); break; default: /* libfdt errs are negative */ if (err < 0) printf("%s: error validating blob: %s\n", filename, fdt_strerror(err)); else printf("%s: unknown load error\n", filename); break; } } static int fdt_load_dtb_overlays_string(const char * filenames) { char *names; char *name, *name_ext; char *comaptr; int err, namesz; debugf("fdt_load_dtb_overlays_string(%s)\n", filenames); names = strdup(filenames); if (names == NULL) return (1); name = names; do { comaptr = strchr(name, ','); if (comaptr) *comaptr = '\0'; err = fdt_load_dtb_overlay(name); if (err == FDT_ERR_NOTFOUND) { /* Allocate enough to append ".dtbo" */ namesz = strlen(name) + 6; name_ext = malloc(namesz); if (name_ext == NULL) { fdt_print_overlay_load_error(err, name); name = comaptr + 1; continue; } snprintf(name_ext, namesz, "%s.dtbo", name); err = fdt_load_dtb_overlay(name_ext); free(name_ext); } /* Catch error with either initial load or fallback load */ if (err != 0) fdt_print_overlay_load_error(err, name); name = comaptr + 1; } while(comaptr); free(names); return (0); } void fdt_apply_overlays() { struct preloaded_file *fp; size_t max_overlay_size, next_fdtp_size; size_t current_fdtp_size; void *current_fdtp; void *next_fdtp; void *overlay; int rv; if ((fdtp == NULL) || (fdtp_size == 0)) return; max_overlay_size = 0; for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { if (max_overlay_size < fp->f_size) max_overlay_size = fp->f_size; } /* Nothing to apply */ if (max_overlay_size == 0) return; overlay = malloc(max_overlay_size); if (overlay == NULL) { printf("failed to allocate memory for DTB blob with overlays\n"); return; } current_fdtp = fdtp; current_fdtp_size = fdtp_size; for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { printf("applying DTB overlay '%s'\n", fp->f_name); next_fdtp_size = current_fdtp_size + fp->f_size; next_fdtp = malloc(next_fdtp_size); if (next_fdtp == NULL) { /* * Output warning, then move on to applying other * overlays in case this one is simply too large. */ printf("failed to allocate memory for overlay base\n"); continue; } rv = fdt_open_into(current_fdtp, next_fdtp, next_fdtp_size); if (rv != 0) { free(next_fdtp); printf("failed to open base dtb into overlay base\n"); continue; } COPYOUT(fp->f_addr, overlay, fp->f_size); /* Both overlay and next_fdtp may be modified in place */ rv = fdt_overlay_apply(next_fdtp, overlay); if (rv == 0) { /* Rotate next -> current */ if (current_fdtp != fdtp) free(current_fdtp); current_fdtp = next_fdtp; current_fdtp_size = next_fdtp_size; } else { /* * Assume here that the base we tried to apply on is * either trashed or in an inconsistent state. Trying to * load it might work, but it's better to discard it and * play it safe. */ free(next_fdtp); printf("failed to apply overlay: %s\n", fdt_strerror(rv)); } } /* We could have failed to apply all overlays; then we do nothing */ if (current_fdtp != fdtp) { free(fdtp); fdtp = current_fdtp; fdtp_size = current_fdtp_size; } free(overlay); } 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 %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' " + snprintf(command_errbuf, sizeof(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 : " + snprintf(command_errbuf, sizeof(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 endianness, 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 endianness, 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); } } void fdt_load_dtb_overlays(const char *extras) { const char *s; /* Any extra overlays supplied by pre-loader environment */ if (extras != NULL && *extras != '\0') { printf("Loading DTB overlays: '%s'\n", extras); fdt_load_dtb_overlays_string(extras); } /* Any overlays supplied by loader environment */ s = getenv("fdt_overlays"); if (s != NULL && *s != '\0') { printf("Loading DTB overlays: '%s'\n", s); fdt_load_dtb_overlays_string(s); } } /* * 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); + snprintf(command_errbuf, sizeof(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); + snprintf(command_errbuf, sizeof(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); + snprintf(command_errbuf, sizeof(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); if (pager_output(line)) goto out; sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); if (pager_output(line)) goto out; sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); if (pager_output(line)) goto out; sprintf(line, " off_dt_struct = 0x%08x\n", fdt_off_dt_struct(fdtp)); if (pager_output(line)) goto out; sprintf(line, " off_dt_strings = 0x%08x\n", fdt_off_dt_strings(fdtp)); if (pager_output(line)) goto out; sprintf(line, " off_mem_rsvmap = 0x%08x\n", fdt_off_mem_rsvmap(fdtp)); if (pager_output(line)) goto out; sprintf(line, " version = %d\n", ver); if (pager_output(line)) goto out; sprintf(line, " last compatible version = %d\n", fdt_last_comp_version(fdtp)); if (pager_output(line)) goto out; if (ver >= 2) { sprintf(line, " boot_cpuid = %d\n", fdt_boot_cpuid_phys(fdtp)); if (pager_output(line)) goto out; } if (ver >= 3) { sprintf(line, " size_dt_strings = %d\n", fdt_size_dt_strings(fdtp)); if (pager_output(line)) goto out; } if (ver >= 17) { sprintf(line, " size_dt_struct = %d\n", fdt_size_dt_struct(fdtp)); if (pager_output(line)) goto out; } out: 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; 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); + snprintf(command_errbuf, sizeof(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, NULL); 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); + snprintf(command_errbuf, sizeof(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); + snprintf(command_errbuf, sizeof(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) ? + snprintf(command_errbuf, sizeof(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) { if (pager_output("Reserved memory regions:\n")) goto out; 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); if (pager_output(line)) goto out; } } else pager_output("No reserved memory regions\n"); out: pager_close(); return (CMD_OK); } static int fdt_cmd_nyi(int argc, char *argv[]) { printf("command not yet implemented\n"); return (CMD_ERROR); } Index: stable/11/sys/boot/forth/loader.4th =================================================================== --- stable/11/sys/boot/forth/loader.4th (revision 329009) +++ stable/11/sys/boot/forth/loader.4th (revision 329010) @@ -1,259 +1,263 @@ \ Copyright (c) 1999 Daniel C. Sobral \ Copyright (c) 2011-2015 Devin Teske \ 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$ only forth definitions s" arch-i386" environment? [if] [if] s" loader_version" environment? [if] 11 < [if] .( Loader version 1.1+ required) cr abort [then] [else] .( Could not get loader version!) cr abort [then] [then] [then] 256 dictthreshold ! \ 256 cells minimum free space 2048 dictincrease ! \ 2048 additional cells each time include /boot/support.4th include /boot/color.4th include /boot/delay.4th include /boot/check-password.4th only forth definitions : bootmsg ( -- ) loader_color? dup ( -- bool bool ) if 7 fg 4 bg then ." Booting..." if me then cr ; : try-menu-unset \ menu-unset may not be present s" beastie_disable" getenv dup -1 <> if s" YES" compare-insensitive 0= if exit then else drop then s" menu-unset" sfind if execute else drop then s" menusets-unset" sfind if execute else drop then ; only forth also support-functions also builtins definitions : boot 0= if ( interpreted ) get_arguments then \ Unload only if a path was passed dup if >r over r> swap c@ [char] - <> if 0 1 unload drop else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then else s" kernelname" getenv? if ( a kernel has been loaded ) try-menu-unset bootmsg 1 boot exit then load_kernel_and_modules ?dup if exit then try-menu-unset bootmsg 0 1 boot exit then load_kernel_and_modules ?dup 0= if bootmsg 0 1 boot then ; \ ***** boot-conf \ \ Prepares to boot as specified by loaded configuration files. : boot-conf 0= if ( interpreted ) get_arguments then 0 1 unload drop load_kernel_and_modules ?dup 0= if 0 1 autoboot then ; also forth definitions previous builtin: boot builtin: boot-conf only forth definitions also support-functions \ ***** start \ \ Initializes support.4th global variables, sets loader_conf_files, \ processes conf files, and, if any one such file was successfully \ read to the end, loads kernel and modules. : start ( -- ) ( throws: abort & user-defined ) s" /boot/defaults/loader.conf" initialize include_conf_files include_nextboot_file + \ If the user defined a post-initialize hook, call it now + s" post-initialize" sfind if execute else drop then \ Will *NOT* try to load kernel and modules if no configuration file \ was successfully loaded! any_conf_read? if s" loader_delay" getenv -1 = if load_xen_throw load_kernel load_modules else drop ." Loading Kernel and Modules (Ctrl-C to Abort)" cr s" also support-functions" evaluate s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate s" set delay_showdots" evaluate delay_execute then then ; \ ***** initialize \ \ Overrides support.4th initialization word with one that does \ everything start one does, short of loading the kernel and -\ modules. Returns a flag +\ modules. Returns a flag. : initialize ( -- flag ) s" /boot/defaults/loader.conf" initialize include_conf_files include_nextboot_file + \ If the user defined a post-initialize hook, call it now + s" post-initialize" sfind if execute else drop then any_conf_read? ; \ ***** read-conf \ \ Read a configuration file, whose name was specified on the command \ line, if interpreted, or given on the stack, if compiled in. : (read-conf) ( addr len -- ) conf_files string= include_conf_files \ Will recurse on new loader_conf_files definitions ; : read-conf ( | addr len -- ) ( throws: abort & user-defined ) state @ if \ Compiling postpone (read-conf) else \ Interpreting bl parse (read-conf) then ; immediate \ show, enable, disable, toggle module loading. They all take module from \ the next word : set-module-flag ( module_addr val -- ) \ set and print flag over module.flag ! dup module.name strtype module.flag @ if ." will be loaded" else ." will not be loaded" then cr ; : enable-module find-module ?dup if true set-module-flag then ; : disable-module find-module ?dup if false set-module-flag then ; : toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; \ ***** show-module \ \ Show loading information about a module. : show-module ( -- ) find-module ?dup if show-one-module then ; \ Words to be used inside configuration files : retry false ; \ For use in load error commands : ignore true ; \ For use in load error commands \ Return to strict forth vocabulary : #type over - >r type r> spaces ; : .? 2 spaces 2swap 15 #type 2 spaces type cr ; \ Execute the ? command to print all the commands defined in \ C, then list the ones we support here. Please note that this \ doesn't use pager_* routines that the C implementation of ? \ does, so these will always appear, even if you stop early \ there. And they may cause the commands to scroll off the \ screen if the number of commands modulus LINES is close \ to LINEs.... : ? ['] ? execute s" boot-conf" s" load kernel and modules, then autoboot" .? s" read-conf" s" read a configuration file" .? s" enable-module" s" enable loading of a module" .? s" disable-module" s" disable loading of a module" .? s" toggle-module" s" toggle loading of a module" .? s" show-module" s" show module load data" .? s" try-include" s" try to load/interpret files" .? ; : try-include ( -- ) \ see loader.4th(8) ['] include ( -- xt ) \ get the execution token of `include' catch ( xt -- exception# | 0 ) if \ failed LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) \ ... prevents words unused by `include' from being interpreted then ; immediate \ interpret immediately for access to `source' (aka tib) only forth definitions Index: stable/11/sys/boot/i386/Makefile.inc =================================================================== --- stable/11/sys/boot/i386/Makefile.inc (revision 329009) +++ stable/11/sys/boot/i386/Makefile.inc (revision 329010) @@ -1,31 +1,36 @@ # Common defines for all of /sys/boot/i386/ # # $FreeBSD$ BINDIR?= /boot LOADER_ADDRESS?=0x200000 CFLAGS+= -march=i386 -ffreestanding CFLAGS.gcc+= -mpreferred-stack-boundary=2 CFLAGS+= ${CFLAGS_NO_SIMD} -msoft-float LDFLAGS+= -nostdlib .if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -m32 ACFLAGS+= -m32 # LD_FLAGS is passed directly to ${LD}, not via ${CC}: LD_FLAGS+= -m elf_i386_fbsd AFLAGS+= --32 .endif # BTX components .if exists(${.OBJDIR}/../btx) BTXDIR= ${.OBJDIR}/../btx .else BTXDIR= ${.CURDIR}/../btx .endif BTXLDR= ${BTXDIR}/btxldr/btxldr BTXKERN= ${BTXDIR}/btx/btx BTXCRT= ${BTXDIR}/lib/crt0.o +# compact binary with no padding between text, data, bss +LDSCRIPT= ${SRCTOP}/sys/boot/i386/boot.ldscript +LDFLAGS_BIN=-e start -Ttext ${ORG} -Wl,-T,${LDSCRIPT},-S,--oformat,binary +LD_FLAGS_BIN=-static -T ${LDSCRIPT} --gc-sections + .include "../Makefile.inc" Index: stable/11/sys/boot/i386/boot.ldscript =================================================================== --- stable/11/sys/boot/i386/boot.ldscript (nonexistent) +++ stable/11/sys/boot/i386/boot.ldscript (revision 329010) @@ -0,0 +1,11 @@ +/* $FreeBSD$ */ +/* Merge text, data and bss together almost no padding */ +OUTPUT_FORMAT("elf32-i386-freebsd") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS { + . = 0x08048000 + SIZEOF_HEADERS; + .text : { *(.text) } =0x90909090 /* Pad with nops, if needed */ + .data : { *(.data) } _edata = .; + .bss : { *(.bss) } _end = .; +} Property changes on: stable/11/sys/boot/i386/boot.ldscript ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/sys/boot/i386/boot0/Makefile =================================================================== --- stable/11/sys/boot/i386/boot0/Makefile (revision 329009) +++ stable/11/sys/boot/i386/boot0/Makefile (revision 329010) @@ -1,82 +1,83 @@ # $FreeBSD$ PROG?= boot0 STRIP= BINMODE=${NOBINMODE} MAN= SRCS= ${PROG}.S # Additional options that you can specify with make OPTS="..." # (these only apply to boot0.S) # # -DVOLUME_SERIAL support volume serial number (NT, XP, Vista) # -DSIO do I/O using COM1: # -DPXE fallback to INT18/PXE with F6 # -DCHECK_DRIVE enable checking drive number # -DONLY_F_KEYS accept only Fx keys in console # -DTEST print drive number on entry # OPTS ?= -DVOLUME_SERIAL -DPXE CFLAGS += ${OPTS} # Flags used in the boot0.S code: # 0x0f all valid partitions enabled. # 0x80 'packet', use BIOS EDD (LBA) extensions instead of CHS # to read from disk. boot0.S does not check that the extensions # are supported, but all modern BIOSes should have them. # 0x40 'noupdate', disable writing boot0 back to disk so that # the current selection is not preserved across reboots. # 0x20 'setdrv', override the drive number supplied by the bios # with the one in the boot sector. # Default boot flags: BOOT_BOOT0_FLAGS?= 0x8f # The number of timer ticks to wait for a keypress before assuming the default # selection. Since there are 18.2 ticks per second, the default value of # 0xb6 (182d) corresponds to 10 seconds. BOOT_BOOT0_TICKS?= 0xb6 # The base address that we the boot0 code to to run it. Don't change this # unless you are glutton for punishment. BOOT_BOOT0_ORG?= 0x600 +ORG=${BOOT_BOOT0_ORG} # Comm settings for boot0sio. # Bit(s) Description # 7-5 data rate (110,150,300,600,1200,2400,4800,9600 bps) # 4-3 parity (00 or 10 = none, 01 = odd, 11 = even) # 2 stop bits (set = 2, clear = 1) # 1-0 data bits (00 = 5, 01 = 6, 10 = 7, 11 = 8) .if !defined(BOOT_BOOT0_COMCONSOLE_SPEED) BOOT_COMCONSOLE_SPEED?= 9600 .if ${BOOT_COMCONSOLE_SPEED} == 9600 BOOT_BOOT0_COMCONSOLE_SPEED= "7 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 4800 BOOT_BOOT0_COMCONSOLE_SPEED= "6 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 2400 BOOT_BOOT0_COMCONSOLE_SPEED= "5 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 1200 BOOT_BOOT0_COMCONSOLE_SPEED= "4 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 600 BOOT_BOOT0_COMCONSOLE_SPEED= "3 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 300 BOOT_BOOT0_COMCONSOLE_SPEED= "2 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 150 BOOT_BOOT0_COMCONSOLE_SPEED= "1 << 5 + 3" .elif ${BOOT_COMCONSOLE_SPEED} == 110 BOOT_BOOT0_COMCONSOLE_SPEED= "0 << 5 + 3" .else BOOT_BOOT0_COMCONSOLE_SPEED= "7 << 5 + 3" .endif .endif CFLAGS+=-DFLAGS=${BOOT_BOOT0_FLAGS} \ -DTICKS=${BOOT_BOOT0_TICKS} \ -DCOMSPEED=${BOOT_BOOT0_COMCONSOLE_SPEED} -LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.boot0.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/boot2/Makefile =================================================================== --- stable/11/sys/boot/i386/boot2/Makefile (revision 329009) +++ stable/11/sys/boot/i386/boot2/Makefile (revision 329010) @@ -1,120 +1,120 @@ # $FreeBSD$ .include FILES= boot boot1 boot2 NM?= nm # A value of 0x80 enables LBA support. BOOT_BOOT1_FLAGS?= 0x80 BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x2000 # Decide level of UFS support. BOOT2_UFS?= UFS1_AND_UFS2 #BOOT2_UFS?= UFS2_ONLY #BOOT2_UFS?= UFS1_ONLY CFLAGS= -fomit-frame-pointer \ -mrtd \ -mregparm=3 \ -DUSE_XREAD \ -D${BOOT2_UFS} \ -DFLAGS=${BOOT_BOOT1_FLAGS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../btx/lib -I. \ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline CFLAGS.gcc+= -Os \ -fno-asynchronous-unwind-tables \ -fno-guess-branch-probability \ -fno-unit-at-a-time \ --param max-inline-insns-single=100 .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} <= 40201 CFLAGS.gcc+= -mno-align-long-strings .endif CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL} -LD_FLAGS=-static -N --gc-sections +LD_FLAGS=${LD_FLAGS_BIN} # Pick up ../Makefile.inc early. .include CLEANFILES= boot boot: boot1 boot2 cat boot1 boot2 > boot CLEANFILES+= boot1 boot1.out boot1.o boot1: boot1.out ${OBJCOPY} -S -O binary boot1.out ${.TARGET} boot1.out: boot1.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o CLEANFILES+= boot2 boot2.ld boot2.ldr boot2.bin boot2.out boot2.o \ boot2.s boot2.s.tmp boot2.h sio.o BOOT2SIZE= 7680 boot2: boot2.ld @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \ echo "$$x bytes available"; test $$x -ge 0 ${DD} if=${.ALLSRC} of=${.TARGET} obs=${BOOT2SIZE} conv=osync boot2.ld: boot2.ldr boot2.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l boot2.ldr \ -o ${.TARGET} -P 1 boot2.bin boot2.ldr: ${DD} if=/dev/zero of=${.TARGET} bs=512 count=1 boot2.bin: boot2.out ${OBJCOPY} -S -O binary boot2.out ${.TARGET} boot2.out: ${BTXCRT} boot2.o sio.o ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} boot2.o: boot2.s ${CC} ${ACFLAGS} -c boot2.s SRCS= boot2.c boot2.h boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c ${CC} ${CFLAGS} -S -o boot2.s.tmp ${.CURDIR}/boot2.c sed -e '/align/d' -e '/nop/d' < boot2.s.tmp > boot2.s rm -f boot2.s.tmp boot2.h: boot1.out ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \ { x = $$1 - ORG1; \ printf("#define XREADORG %#x\n", REL1 + x) }' \ ORG1=`printf "%d" ${ORG1}` \ REL1=`printf "%d" ${REL1}` > ${.TARGET} .if ${MACHINE_CPUARCH} == "amd64" beforedepend boot2.s: machine CLEANFILES+= machine machine: ${.CURDIR}/../../../i386/include .NOMETA ln -sf ${.ALLSRC} ${.TARGET} .endif .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.boot1.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/btx/btx/Makefile =================================================================== --- stable/11/sys/boot/i386/btx/btx/Makefile (revision 329009) +++ stable/11/sys/boot/i386/btx/btx/Makefile (revision 329010) @@ -1,33 +1,33 @@ # $FreeBSD$ PROG= btx INTERNALPROG= MAN= SRCS= btx.S .if defined(BOOT_BTX_NOHANG) BOOT_BTX_FLAGS=0x1 .else BOOT_BTX_FLAGS=0x0 .endif CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} CFLAGS+=-I${.CURDIR}/../../common .if defined(BTX_SERIAL) BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} .endif ORG= 0x9000 -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btx.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/btx/btxldr/Makefile =================================================================== --- stable/11/sys/boot/i386/btx/btxldr/Makefile (revision 329009) +++ stable/11/sys/boot/i386/btx/btxldr/Makefile (revision 329010) @@ -1,20 +1,21 @@ # $FreeBSD$ PROG= btxldr INTERNALPROG= MAN= SRCS= btxldr.S CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} CFLAGS+=-I${.CURDIR}/../../common .if defined(BTXLDR_VERBOSE) CFLAGS+=-DBTXLDR_VERBOSE .endif -LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -Wl,-N,-S,--oformat,binary +ORG=${LOADER_ADDRESS} +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btxldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/btx/btxldr/btxldr.S =================================================================== --- stable/11/sys/boot/i386/btx/btxldr/btxldr.S (revision 329009) +++ stable/11/sys/boot/i386/btx/btxldr/btxldr.S (revision 329010) @@ -1,409 +1,409 @@ /* * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. * * $FreeBSD$ */ #include #define RBX_MUTE 0x10 /* -m */ #define OPT_SET(opt) (1 << (opt)) /* * Prototype BTX loader program, written in a couple of hours. The * real thing should probably be more flexible, and in C. */ /* * Memory locations. */ .set MEM_STUB,0x600 # Real mode stub .set MEM_ESP,0x1000 # New stack pointer .set MEM_TBL,0x5000 # BTX page tables .set MEM_ENTRY,0x9010 # BTX entry point .set MEM_DATA,start+0x1000 # Data segment /* * Segment selectors. */ .set SEL_SCODE,0x8 # 4GB code .set SEL_SDATA,0x10 # 4GB data .set SEL_RCODE,0x18 # 64K code .set SEL_RDATA,0x20 # 64K data /* * Paging constants. */ .set PAG_SIZ,0x1000 # Page size .set PAG_ENT,0x4 # Page entry size /* * Screen constants. */ .set SCR_MAT,0x7 # Mode/attribute .set SCR_COL,0x50 # Columns per row .set SCR_ROW,0x19 # Rows per screen /* * BIOS Data Area locations. */ .set BDA_MEM,0x413 # Free memory .set BDA_SCR,0x449 # Video mode .set BDA_POS,0x450 # Cursor position /* * Required by aout gas inadequacy. */ .set SIZ_STUB,0x1a # Size of stub /* * We expect to be loaded by boot2 at the origin defined in ./Makefile. */ .globl start /* * BTX program loader for ELF clients. */ start: cld # String ops inc testl $OPT_SET(RBX_MUTE), 4(%esp) # Check first argument setnz muted # for RBX_MUTE, set flag movl $m_logo,%esi # Identify call putstr # ourselves movzwl BDA_MEM,%eax # Get base memory shll $0xa,%eax # in bytes movl %eax,%ebp # Base of user stack #ifdef BTXLDR_VERBOSE movl $m_mem,%esi # Display call hexout # amount of call putstr # base memory #endif lgdt gdtdesc # Load new GDT /* * Relocate caller's arguments. */ #ifdef BTXLDR_VERBOSE movl $m_esp,%esi # Display movl %esp,%eax # caller call hexout # stack call putstr # pointer movl $m_args,%esi # Format string leal 0x4(%esp),%ebx # First argument movl $0x6,%ecx # Count start.1: movl (%ebx),%eax # Get argument and addl $0x4,%ebx # bump pointer call hexout # Display it loop start.1 # Till done call putstr # End message #endif movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo cmpl $0x0, %esi # If the bootinfo pointer je start_null_bi # is null, don't copy it movl BI_SIZE(%esi),%ecx # Allocate space subl %ecx,%ebp # for bootinfo movl %ebp,%edi # Destination rep # Copy movsb # it movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer movl %edi,%ebp # Restore base pointer #ifdef BTXLDR_VERBOSE movl $m_rel_bi,%esi # Display movl %ebp,%eax # bootinfo call hexout # relocation call putstr # message #endif start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data jz start_fixed # Skip if the flag is not set addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset leal 0x4(%esp),%esi # Source movl %ebp,%edi # Destination rep # Copy movsb # them #ifdef BTXLDR_VERBOSE movl $m_rel_args,%esi # Display movl %ebp,%eax # argument call hexout # relocation call putstr # message #endif /* * Set up BTX kernel. */ movl $MEM_ESP,%esp # Set up new stack movl $MEM_DATA,%ebx # Data segment movl $m_vers,%esi # Display BTX call putstr # version message movb 0x5(%ebx),%al # Get major version addb $'0',%al # Display call putchr # it movb $'.',%al # And a call putchr # dot movb 0x6(%ebx),%al # Get minor xorb %ah,%ah # version movb $0xa,%dl # Divide divb %dl,%al # by 10 addb $'0',%al # Display call putchr # tens movb %ah,%al # Get units addb $'0',%al # Display call putchr # units call putstr # End message movl %ebx,%esi # BTX image movzwl 0x8(%ebx),%edi # Compute orl $PAG_SIZ/PAG_ENT-1,%edi # the incl %edi # BTX shll $0x2,%edi # load addl $MEM_TBL,%edi # address pushl %edi # Save load address movzwl 0xa(%ebx),%ecx # Image size #ifdef BTXLDR_VERBOSE pushl %ecx # Save image size #endif rep # Relocate movsb # BTX movl %esi,%ebx # Keep place #ifdef BTXLDR_VERBOSE movl $m_rel_btx,%esi # Restore popl %eax # parameters call hexout # and #endif popl %ebp # display #ifdef BTXLDR_VERBOSE movl %ebp,%eax # the call hexout # relocation call putstr # message #endif addl $PAG_SIZ,%ebp # Display #ifdef BTXLDR_VERBOSE movl $m_base,%esi # the movl %ebp,%eax # user call hexout # base call putstr # address #endif /* * Set up ELF-format client program. */ cmpl $0x464c457f,(%ebx) # ELF magic number? je start.3 # Yes movl $e_fmt,%esi # Display error call putstr # message start.2: jmp start.2 # Hang start.3: #ifdef BTXLDR_VERBOSE movl $m_elf,%esi # Display ELF call putstr # message movl $m_segs,%esi # Format string #endif movl 0x1c(%ebx),%edx # Get e_phoff addl %ebx,%edx # To pointer movzwl 0x2c(%ebx),%ecx # Get e_phnum start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? jne start.6 # No #ifdef BTXLDR_VERBOSE movl 0x4(%edx),%eax # Display call hexout # p_offset movl 0x8(%edx),%eax # Display call hexout # p_vaddr movl 0x10(%edx),%eax # Display call hexout # p_filesz movl 0x14(%edx),%eax # Display call hexout # p_memsz call putstr # End message #endif pushl %esi # Save pushl %ecx # working registers movl 0x4(%edx),%esi # Get p_offset addl %ebx,%esi # as pointer movl 0x8(%edx),%edi # Get p_vaddr addl %ebp,%edi # as pointer movl 0x10(%edx),%ecx # Get p_filesz rep # Set up movsb # segment movl 0x14(%edx),%ecx # Any bytes subl 0x10(%edx),%ecx # to zero? jz start.5 # No xorb %al,%al # Then rep # zero stosb # them start.5: popl %ecx # Restore popl %esi # registers start.6: addl $0x20,%edx # To next entry loop start.4 # Till done #ifdef BTXLDR_VERBOSE movl $m_done,%esi # Display done call putstr # message #endif movl $start.8,%esi # Real mode stub movl $MEM_STUB,%edi # Destination movl $start.9-start.8,%ecx # Size rep # Relocate movsb # it ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code .code16 start.8: xorw %ax,%ax # Data movb $SEL_RDATA,%al # selector movw %ax,%ss # Reload SS movw %ax,%ds # Reset movw %ax,%es # other movw %ax,%fs # segment movw %ax,%gs # limits movl %cr0,%eax # Switch to decw %ax # real movl %eax,%cr0 # mode ljmp $0,$MEM_ENTRY # Jump to BTX entry point start.9: .code32 /* * Output message [ESI] followed by EAX in hex. */ hexout: pushl %eax # Save call putstr # Display message popl %eax # Restore pushl %esi # Save pushl %edi # caller's movl $buf,%edi # Buffer pushl %edi # Save call hex32 # To hex xorb %al,%al # Terminate stosb # string popl %esi # Restore hexout.1: lodsb # Get a char cmpb $'0',%al # Leading zero? je hexout.1 # Yes testb %al,%al # End of string? jne hexout.2 # No decl %esi # Undo hexout.2: decl %esi # Adjust for inc call putstr # Display hex popl %edi # Restore popl %esi # caller's ret # To caller /* * Output zero-terminated string [ESI] to the console. */ putstr.0: call putchr # Output char putstr: lodsb # Load char testb %al,%al # End of string? jne putstr.0 # No ret # To caller /* * Output character AL to the console. */ putchr: testb $1,muted # Check muted jnz putchr.5 # do a nop pusha # Save xorl %ecx,%ecx # Zero for loops movb $SCR_MAT,%ah # Mode/attribute movl $BDA_POS,%ebx # BDA pointer movw (%ebx),%dx # Cursor position movl $0xb8000,%edi # Regen buffer (color) cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? jne putchr.1 # No xorw %di,%di # Regen buffer (mono) putchr.1: cmpb $0xa,%al # New line? je putchr.2 # Yes xchgl %eax,%ecx # Save char movb $SCR_COL,%al # Columns per row mulb %dh # * row position addb %dl,%al # + column adcb $0x0,%ah # position shll %eax # * 2 xchgl %eax,%ecx # Swap char, offset movw %ax,(%edi,%ecx,1) # Write attr:char incl %edx # Bump cursor cmpb $SCR_COL,%dl # Beyond row? jb putchr.3 # No putchr.2: xorb %dl,%dl # Zero column incb %dh # Bump row putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? jb putchr.4 # No leal 2*SCR_COL(%edi),%esi # New top line movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move rep # Scroll movsl # screen movb $' ',%al # Space movb $SCR_COL,%cl # Columns to clear rep # Clear stosw # line movb $SCR_ROW-1,%dh # Bottom line putchr.4: movw %dx,(%ebx) # Update position popa # Restore putchr.5: ret # To caller /* * Convert EAX, AX, or AL to hex, saving the result to [EDI]. */ hex32: pushl %eax # Save shrl $0x10,%eax # Do upper call hex16 # 16 popl %eax # Restore hex16: call hex16.1 # Do upper 8 hex16.1: xchgb %ah,%al # Save/restore hex8: pushl %eax # Save shrb $0x4,%al # Do upper call hex8.1 # 4 popl %eax # Restore hex8.1: andb $0xf,%al # Get lower 4 cmpb $0xa,%al # Convert sbbb $0x69,%al # to hex das # digit orb $0x20,%al # To lower case stosb # Save char ret # (Recursive) .data .p2align 4 /* * Global descriptor table. */ gdt: .word 0x0,0x0,0x0,0x0 # Null entry .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA gdt.1: gdtdesc: .word gdt.1-gdt-1 # Limit .long gdt # Base /* * Messages. */ m_logo: .asciz " \nBTX loader 1.00 " m_vers: .asciz "BTX version is \0\n" e_fmt: .asciz "Error: Client format not supported\n" #ifdef BTXLDR_VERBOSE m_mem: .asciz "Starting in protected mode (base mem=\0)\n" m_esp: .asciz "Arguments passed (esp=\0):\n" -m_args: .asciz"\n" +m_args: .asciz "\n" m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" m_base: .asciz "Client base address is \0\n" m_elf: .asciz "Client format is ELF\n" m_segs: .asciz "text segment: offset=" .asciz " vaddr=" .asciz " filesz=" .asciz " memsz=\0\n" .asciz "data segment: offset=" .asciz " vaddr=" .asciz " filesz=" .asciz " memsz=\0\n" m_done: .asciz "Loading complete\n" #endif /* * Flags */ muted: .byte 0x0 /* * Uninitialized data area. */ buf: # Scratch buffer Index: stable/11/sys/boot/i386/cdboot/Makefile =================================================================== --- stable/11/sys/boot/i386/cdboot/Makefile (revision 329009) +++ stable/11/sys/boot/i386/cdboot/Makefile (revision 329010) @@ -1,18 +1,18 @@ # $FreeBSD$ PROG= cdboot STRIP= BINMODE=${NOBINMODE} MAN= SRCS= ${PROG}.S CFLAGS+=-I${.CURDIR}/../common ORG= 0x7c00 -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.cdboot.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/gptboot/Makefile =================================================================== --- stable/11/sys/boot/i386/gptboot/Makefile (revision 329009) +++ stable/11/sys/boot/i386/gptboot/Makefile (revision 329010) @@ -1,92 +1,92 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common ${.CURDIR}/../../common FILES= gptboot MAN= gptboot.8 NM?= nm BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x0 # Decide level of UFS support. GPTBOOT_UFS?= UFS1_AND_UFS2 #GPTBOOT_UFS?= UFS2_ONLY #GPTBOOT_UFS?= UFS1_ONLY CFLAGS= -DBOOTPROG=\"gptboot\" \ -O1 \ -DGPT \ -D${GPTBOOT_UFS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../common \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -I${.CURDIR}/../../.. \ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline -Wno-pointer-sign CFLAGS.gcc+= --param max-inline-insns-single=100 .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT CFLAGS+= -I${.CURDIR}/../../geli LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a .PATH: ${.CURDIR}/../../../opencrypto OPENCRYPTO_XTS= xform_aes_xts.o .endif -LD_FLAGS=-static -N --gc-sections +LD_FLAGS=${LD_FLAGS_BIN} LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a # Pick up ../Makefile.inc early. .include CLEANFILES= gptboot gptboot: gptldr.bin gptboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \ -o ${.TARGET} gptboot.bin CLEANFILES+= gptldr.bin gptldr.out gptldr.o gptldr.bin: gptldr.out ${OBJCOPY} -S -O binary gptldr.out ${.TARGET} gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \ cons.o util.o ${OPENCRYPTO_XTS} gptboot.bin: gptboot.out ${OBJCOPY} -S -O binary gptboot.out ${.TARGET} gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o util.o ${OPENCRYPTO_XTS} ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT} gptboot.o: ${.CURDIR}/../../common/ufsread.c .if ${MACHINE_CPUARCH} == "amd64" beforedepend gptboot.o: machine CLEANFILES+= machine machine: .NOMETA ln -sf ${.CURDIR}/../../../i386/include machine .endif .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.gptldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/gptzfsboot/Makefile =================================================================== --- stable/11/sys/boot/i386/gptzfsboot/Makefile (revision 329009) +++ stable/11/sys/boot/i386/gptzfsboot/Makefile (revision 329010) @@ -1,102 +1,102 @@ # $FreeBSD$ .include .PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot \ ${.CURDIR}/../zfsboot ${.CURDIR}/../common \ ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein FILES= gptzfsboot MAN= gptzfsboot.8 NM?= nm BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x0 CFLAGS= -DBOOTPROG=\"gptzfsboot\" \ -O1 \ -DGPT -DZFS -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ -I${.CURDIR}/../../../crypto/skein \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -I${.CURDIR}/../../.. \ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline -Wno-pointer-sign .if ${COMPILER_TYPE} == "clang" || \ (${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201) CFLAGS+= -Wno-tentative-definition-incomplete-type .endif # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT CFLAGS+= -I${.CURDIR}/../../geli LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a .PATH: ${.CURDIR}/../../../opencrypto OPENCRYPTO_XTS= xform_aes_xts.o .endif CFLAGS.gcc+= --param max-inline-insns-single=100 -LD_FLAGS=-static -N --gc-sections +LD_FLAGS=${LD_FLAGS_BIN} LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a # Pick up ../Makefile.inc early. .include CLEANFILES= gptzfsboot gptzfsboot: gptldr.bin gptzfsboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \ -o ${.TARGET} gptzfsboot.bin CLEANFILES+= gptldr.bin gptldr.out gptldr.o gptldr.bin: gptldr.out ${OBJCOPY} -S -O binary gptldr.out ${.TARGET} gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \ drv.o gpt.o util.o skein.o skein_block.o ${OPENCRYPTO_XTS} gptzfsboot.bin: gptzfsboot.out ${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET} gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o \ skein.o skein_block.o ${OPENCRYPTO_XTS} ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT} zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c .if ${MACHINE_CPUARCH} == "amd64" beforedepend zfsboot.o: machine CLEANFILES+= machine machine: .NOMETA ln -sf ${.CURDIR}/../../../i386/include machine .endif .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.gptldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/libi386/biosdisk.c =================================================================== --- stable/11/sys/boot/i386/libi386/biosdisk.c (revision 329009) +++ stable/11/sys/boot/i386/libi386/biosdisk.c (revision 329010) @@ -1,931 +1,946 @@ /*- * Copyright (c) 1998 Michael Smith * 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. */ #include __FBSDID("$FreeBSD$"); /* * BIOS disk device handling. * * Ideas and algorithms from: * * - NetBSD libi386/biosdisk.c * - FreeBSD biosboot/disk.c * */ #include #include #include #include #include #include #include #include "disk.h" #include "libi386.h" #ifdef LOADER_GELI_SUPPORT #include "cons.h" #include "drv.h" #include "gpt.h" #include "part.h" #include struct pentry { struct ptable_entry part; uint64_t flags; union { uint8_t bsd; uint8_t mbr; uuid_t gpt; uint16_t vtoc8; } type; STAILQ_ENTRY(pentry) entry; }; struct ptable { enum ptable_type type; uint16_t sectorsize; uint64_t sectors; STAILQ_HEAD(, pentry) entries; }; #include "geliboot.c" #endif /* LOADER_GELI_SUPPORT */ CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc)); #define BIOS_NUMDRIVES 0x475 #define BIOSDISK_SECSIZE 512 #define BUFSIZE (1 * BIOSDISK_SECSIZE) #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ #define WDMAJOR 0 /* major numbers for devices we frontend for */ #define WFDMAJOR 1 #define FDMAJOR 2 #define DAMAJOR 4 #ifdef DISK_DEBUG # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DEBUG(fmt, args...) #endif /* * List of BIOS devices, translation from disk unit number to * BIOS unit number. */ static struct bdinfo { int bd_unit; /* BIOS unit number */ int bd_cyl; /* BIOS geometry */ int bd_hds; int bd_sec; int bd_flags; #define BD_MODEINT13 0x0000 #define BD_MODEEDD1 0x0001 #define BD_MODEEDD3 0x0002 #define BD_MODEMASK 0x0003 #define BD_FLOPPY 0x0004 int bd_type; /* BIOS 'drive type' (floppy only) */ uint16_t bd_sectorsize; /* Sector size */ uint64_t bd_sectors; /* Disk size */ int bd_open; /* reference counter */ void *bd_bcache; /* buffer cache data */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; #define BD(dev) (bdinfo[(dev)->d_unit]) static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest); static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest); static int bd_int13probe(struct bdinfo *bd); static int bd_init(void); static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int bd_open(struct open_file *f, ...); static int bd_close(struct open_file *f); static int bd_ioctl(struct open_file *f, u_long cmd, void *data); static int bd_print(int verbose); static void bd_cleanup(void); #ifdef LOADER_GELI_SUPPORT static enum isgeli { ISGELI_UNKNOWN, ISGELI_NO, ISGELI_YES }; static enum isgeli geli_status[MAXBDDEV][MAXTBLENTS]; int bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf, size_t bytes); #endif /* LOADER_GELI_SUPPORT */ struct devsw biosdisk = { "disk", DEVT_DISK, bd_init, bd_strategy, bd_open, bd_close, bd_ioctl, bd_print, bd_cleanup }; /* * Translate between BIOS device numbers and our private unit numbers. */ int bd_bios2unit(int biosdev) { int i; DEBUG("looking for bios device 0x%x", biosdev); for (i = 0; i < nbdinfo; i++) { DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); if (bdinfo[i].bd_unit == biosdev) return (i); } return (-1); } int bd_unit2bios(int unit) { if ((unit >= 0) && (unit < nbdinfo)) return (bdinfo[unit].bd_unit); return (-1); } /* * Quiz the BIOS for disk devices, save a little info about them. */ static int bd_init(void) { int base, unit, nfd = 0; #ifdef LOADER_GELI_SUPPORT geli_init(); #endif /* sequence 0, 0x80 */ for (base = 0; base <= 0x80; base += 0x80) { for (unit = base; (nbdinfo < MAXBDDEV); unit++) { #ifndef VIRTUALBOX /* * Check the BIOS equipment list for number * of fixed disks. */ if(base == 0x80 && (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) break; #endif bdinfo[nbdinfo].bd_open = 0; bdinfo[nbdinfo].bd_bcache = NULL; bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0; if (!bd_int13probe(&bdinfo[nbdinfo])) break; /* XXX we need "disk aliases" to make this simpler */ printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ? ('A' + unit): ('C' + unit - 0x80), nbdinfo); nbdinfo++; if (base == 0x80) nfd++; } } bcache_add_dev(nbdinfo); return(0); } static void bd_cleanup(void) { disk_cleanup(&biosdisk); } /* * Try to detect a device supported by the legacy int13 BIOS */ static int bd_int13probe(struct bdinfo *bd) { struct edd_params params; + int ret = 1; /* assume success */ v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = bd->bd_unit; v86int(); + /* Don't error out if we get bad sector number, try EDD as well */ if (V86_CY(v86.efl) || /* carry set */ - (v86.ecx & 0x3f) == 0 || /* absurd sector number */ (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */ return (0); /* skip device */ + if ((v86.ecx & 0x3f) == 0) /* absurd sector number */ + ret = 0; /* set error */ + /* Convert max cyl # -> # of cylinders */ bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; /* Convert max head # -> # of heads */ bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; bd->bd_sec = v86.ecx & 0x3f; bd->bd_type = v86.ebx & 0xff; bd->bd_flags |= BD_MODEINT13; /* Calculate sectors count from the geometry */ bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec; bd->bd_sectorsize = BIOSDISK_SECSIZE; DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, bd->bd_hds, bd->bd_sec); /* Determine if we can use EDD with this device. */ v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4100; v86.edx = bd->bd_unit; v86.ebx = 0x55aa; v86int(); if (V86_CY(v86.efl) || /* carry set */ (v86.ebx & 0xffff) != 0xaa55 || /* signature */ (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) - return (1); + return (ret); /* return code from int13 AH=08 */ + /* EDD supported */ bd->bd_flags |= BD_MODEEDD1; if ((v86.eax & 0xff00) >= 0x3000) bd->bd_flags |= BD_MODEEDD3; /* Get disk params */ params.len = sizeof(struct edd_params); v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x4800; v86.edx = bd->bd_unit; v86.ds = VTOPSEG(¶ms); v86.esi = VTOPOFF(¶ms); v86int(); if (!V86_CY(v86.efl)) { - bd->bd_sectors = params.sectors; + uint64_t total; + + if (params.sectors != 0) + bd->bd_sectors = params.sectors; + + total = (uint64_t)params.cylinders * + params.heads * params.sectors_per_track; + if (bd->bd_sectors < total) + bd->bd_sectors = total; + bd->bd_sectorsize = params.sector_size; + ret = 1; } DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u", bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize); - return (1); + return (ret); } /* * Print information about disks */ static int bd_print(int verbose) { static char line[80]; struct disk_devdesc dev; int i, ret = 0; if (nbdinfo == 0) return (0); printf("%s devices:", biosdisk.dv_name); if ((ret = pager_output("\n")) != 0) return (ret); for (i = 0; i < nbdinfo; i++) { snprintf(line, sizeof(line), " disk%d: BIOS drive %c (%ju X %u):\n", i, (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): ('C' + bdinfo[i].bd_unit - 0x80), (uintmax_t)bdinfo[i].bd_sectors, bdinfo[i].bd_sectorsize); if ((ret = pager_output(line)) != 0) break; dev.d_dev = &biosdisk; dev.d_unit = i; dev.d_slice = -1; dev.d_partition = -1; if (disk_open(&dev, bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, bdinfo[i].bd_sectorsize, (bdinfo[i].bd_flags & BD_FLOPPY) ? DISK_F_NOCACHE: 0) == 0) { snprintf(line, sizeof(line), " disk%d", i); ret = disk_print(&dev, line, verbose); disk_close(&dev); if (ret != 0) return (ret); } } return (ret); } /* * Attempt to open the disk described by (dev) for use by (f). * * Note that the philosophy here is "give them exactly what * they ask for". This is necessary because being too "smart" * about what the user might want leads to complications. * (eg. given no slice or partition value, with a disk that is * sliced - are they after the first BSD slice, or the DOS * slice before it?) */ static int bd_open(struct open_file *f, ...) { struct disk_devdesc *dev, rdev; int err, g_err; va_list ap; va_start(ap, f); dev = va_arg(ap, struct disk_devdesc *); va_end(ap); if (dev->d_unit < 0 || dev->d_unit >= nbdinfo) return (EIO); BD(dev).bd_open++; if (BD(dev).bd_bcache == NULL) BD(dev).bd_bcache = bcache_allocate(); err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ? DISK_F_NOCACHE: 0); #ifdef LOADER_GELI_SUPPORT static char gelipw[GELI_PW_MAXLEN]; char *passphrase; if (err) return (err); /* if we already know there is no GELI, skip the rest */ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_UNKNOWN) return (err); struct dsk dskp; struct ptable *table = NULL; struct ptable_entry part; struct pentry *entry; int geli_part = 0; dskp.drive = bd_unit2bios(dev->d_unit); dskp.type = dev->d_type; dskp.unit = dev->d_unit; dskp.slice = dev->d_slice; dskp.part = dev->d_partition; dskp.start = dev->d_offset; memcpy(&rdev, dev, sizeof(rdev)); /* to read the GPT table, we need to read the first sector */ rdev.d_offset = 0; /* We need the LBA of the end of the partition */ table = ptable_open(&rdev, BD(dev).bd_sectors, BD(dev).bd_sectorsize, ptblread); if (table == NULL) { DEBUG("Can't read partition table"); /* soft failure, return the exit status of disk_open */ return (err); } if (table->type == PTABLE_GPT) dskp.part = 255; STAILQ_FOREACH(entry, &table->entries, entry) { dskp.slice = entry->part.index; dskp.start = entry->part.start; if (is_geli(&dskp) == 0) { geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; return (0); } if (geli_taste(bios_read, &dskp, entry->part.end - entry->part.start) == 0) { if ((passphrase = getenv("kern.geom.eli.passphrase")) != NULL) { /* Use the cached passphrase */ bcopy(passphrase, &gelipw, GELI_PW_MAXLEN); } if (geli_passphrase(&gelipw, dskp.unit, 'p', (dskp.slice > 0 ? dskp.slice : dskp.part), &dskp) == 0) { setenv("kern.geom.eli.passphrase", &gelipw, 1); bzero(gelipw, sizeof(gelipw)); geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; geli_part++; } } else geli_status[dev->d_unit][dskp.slice] = ISGELI_NO; } /* none of the partitions on this disk have GELI */ if (geli_part == 0) { /* found no GELI */ geli_status[dev->d_unit][dev->d_slice] = ISGELI_NO; } #endif /* LOADER_GELI_SUPPORT */ return (err); } static int bd_close(struct open_file *f) { struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; BD(dev).bd_open--; if (BD(dev).bd_open == 0) { bcache_free(BD(dev).bd_bcache); BD(dev).bd_bcache = NULL; } return (disk_close(dev)); } static int bd_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 = BD(dev).bd_sectorsize; break; case DIOCGMEDIASIZE: *(off_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; break; default: return (ENOTTY); } return (0); } static int bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata bcd; struct disk_devdesc *dev; dev = (struct disk_devdesc *)devdata; bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; bcd.dv_cache = BD(dev).bd_bcache; return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, size, buf, rsize)); } static int bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; int blks, remaining; #ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ char fragbuf[BIOSDISK_SECSIZE]; size_t fragsize; fragsize = size % BIOSDISK_SECSIZE; #else if (size % BD(dev).bd_sectorsize) panic("bd_strategy: %d bytes I/O not multiple of block size", size); #endif DEBUG("open_disk %p", dev); blks = size / BD(dev).bd_sectorsize; if (rsize) *rsize = 0; /* * Perform partial read to prevent read-ahead crossing * the end of disk - or any 32 bit aliases of the end. * Signed arithmetic is used to handle wrap-around cases * like we do for TCP sequence numbers. */ remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */ if (remaining > 0 && remaining < blks) { blks = remaining; size = blks * BD(dev).bd_sectorsize; DEBUG("short read %d", blks); } switch(rw){ case F_READ: DEBUG("read %d from %lld to %p", blks, dblk, buf); if (blks && bd_read(dev, dblk, blks, buf)) { DEBUG("read error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ DEBUG("bd_strategy: frag read %d from %d+%d to %p", fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { DEBUG("frag read error"); return(EIO); } bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); #endif break; case F_WRITE : DEBUG("write %d from %d to %p", blks, dblk, buf); if (blks && bd_write(dev, dblk, blks, buf)) { DEBUG("write error"); return (EIO); } #ifdef BD_SUPPORT_FRAGS if(fragsize) { DEBUG("Attempted to write a frag"); return (EIO); } #endif break; default: /* DO NOTHING */ return (EROFS); } if (rsize) *rsize = size; return (0); } /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ #define FLOPPY_BOUNCEBUF 18 static int bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) { static struct edd_packet packet; packet.len = sizeof(struct edd_packet); packet.count = blks; packet.off = VTOPOFF(dest); packet.seg = VTOPSEG(dest); packet.lba = dblk; v86.ctl = V86_FLAGS; v86.addr = 0x13; if (write) /* Should we Write with verify ?? 0x4302 ? */ v86.eax = 0x4300; else v86.eax = 0x4200; v86.edx = BD(dev).bd_unit; v86.ds = VTOPSEG(&packet); v86.esi = VTOPOFF(&packet); v86int(); return (V86_CY(v86.efl)); } static int bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) { u_int x, bpc, cyl, hd, sec; bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */ x = dblk; cyl = x / bpc; /* block # / blocks per cylinder */ x %= bpc; /* block offset into cylinder */ hd = x / BD(dev).bd_sec; /* offset / blocks per track */ sec = x % BD(dev).bd_sec; /* offset into track */ /* correct sector number for 1-based BIOS numbering */ sec++; if (cyl > 1023) /* CHS doesn't support cylinders > 1023. */ return (1); v86.ctl = V86_FLAGS; v86.addr = 0x13; if (write) v86.eax = 0x300 | blks; else v86.eax = 0x200 | blks; v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; v86.edx = (hd << 8) | BD(dev).bd_unit; v86.es = VTOPSEG(dest); v86.ebx = VTOPOFF(dest); v86int(); return (V86_CY(v86.efl)); } static int bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) { u_int x, sec, result, resid, retry, maxfer; caddr_t p, xp, bbuf, breg; /* Just in case some idiot actually tries to read/write -1 blocks... */ if (blks < 0) return (-1); resid = blks; p = dest; /* Decide whether we have to bounce */ if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 && (VTOP(dest) >> 16) != (VTOP(dest + blks * BD(dev).bd_sectorsize) >> 16))) { /* * There is a 64k physical boundary somewhere in the * destination buffer, or the destination buffer is above * first 1MB of physical memory so we have to arrange a * suitable bounce buffer. Allocate a buffer twice as large * as we need to. Use the bottom half unless there is a break * there, in which case we use the top half. */ x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); bbuf = alloca(x * 2 * BD(dev).bd_sectorsize); if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(bbuf + x * BD(dev).bd_sectorsize) & 0xffff0000)) { breg = bbuf; } else { breg = bbuf + x * BD(dev).bd_sectorsize; } maxfer = x; /* limit transfers to bounce region size */ } else { breg = bbuf = NULL; maxfer = 0; } while (resid > 0) { /* * Play it safe and don't cross track boundaries. * (XXX this is probably unnecessary) */ sec = dblk % BD(dev).bd_sec; /* offset into track */ x = min(BD(dev).bd_sec - sec, resid); if (maxfer > 0) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ xp = bbuf == NULL ? p : breg; /* * Put your Data In, Put your Data out, * Put your Data In, and shake it all about */ if (write && bbuf != NULL) bcopy(p, breg, x * BD(dev).bd_sectorsize); /* * Loop retrying the operation a couple of times. The BIOS * may also retry. */ for (retry = 0; retry < 3; retry++) { /* if retrying, reset the drive */ if (retry > 0) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0; v86.edx = BD(dev).bd_unit; v86int(); } if (BD(dev).bd_flags & BD_MODEEDD1) result = bd_edd_io(dev, dblk, x, xp, write); else result = bd_chs_io(dev, dblk, x, xp, write); if (result == 0) break; } if (write) DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x, p, VTOP(p), dblk, result ? "failed" : "ok"); else DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, dblk, p, VTOP(p), result ? "failed" : "ok"); if (result) { return(-1); } if (!write && bbuf != NULL) bcopy(breg, p, x * BD(dev).bd_sectorsize); p += (x * BD(dev).bd_sectorsize); dblk += x; resid -= x; } /* hexdump(dest, (blks * BD(dev).bd_sectorsize)); */ return(0); } static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) { #ifdef LOADER_GELI_SUPPORT struct dsk dskp; off_t p_off, diff; daddr_t alignlba; int err, n, alignblks; char *tmpbuf; /* if we already know there is no GELI, skip the rest */ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_YES) return (bd_io(dev, dblk, blks, dest, 0)); if (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) { /* * Align reads to DEV_GELIBOOT_BSIZE bytes because partial * sectors cannot be decrypted. Round the requested LBA down to * nearest multiple of DEV_GELIBOOT_BSIZE bytes. */ alignlba = rounddown2(dblk * BD(dev).bd_sectorsize, DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize; /* * Round number of blocks to read up to nearest multiple of * DEV_GELIBOOT_BSIZE */ diff = (dblk - alignlba) * BD(dev).bd_sectorsize; alignblks = roundup2(blks * BD(dev).bd_sectorsize + diff, DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize; /* * If the read is rounded up to a larger size, use a temporary * buffer here because the buffer provided by the caller may be * too small. */ if (diff == 0) { tmpbuf = dest; } else { tmpbuf = malloc(alignblks * BD(dev).bd_sectorsize); if (tmpbuf == NULL) { return (-1); } } err = bd_io(dev, alignlba, alignblks, tmpbuf, 0); if (err) return (err); dskp.drive = bd_unit2bios(dev->d_unit); dskp.type = dev->d_type; dskp.unit = dev->d_unit; dskp.slice = dev->d_slice; dskp.part = dev->d_partition; dskp.start = dev->d_offset; /* GELI needs the offset relative to the partition start */ p_off = alignlba - dskp.start; err = geli_read(&dskp, p_off * BD(dev).bd_sectorsize, tmpbuf, alignblks * BD(dev).bd_sectorsize); if (err) return (err); if (tmpbuf != dest) { bcopy(tmpbuf + diff, dest, blks * BD(dev).bd_sectorsize); free(tmpbuf); } return (0); } #endif /* LOADER_GELI_SUPPORT */ return (bd_io(dev, dblk, blks, dest, 0)); } static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) { return (bd_io(dev, dblk, blks, dest, 1)); } /* * Return the BIOS geometry of a given "fixed drive" in a format * suitable for the legacy bootinfo structure. Since the kernel is * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we * prefer to get the information directly, rather than rely on being * able to put it together from information already maintained for * different purposes and for a probably different number of drives. * * For valid drives, the geometry is expected in the format (31..0) * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are * indicated by returning the geometry of a "1.2M" PC-format floppy * disk. And, incidentally, what is returned is not the geometry as * such but the highest valid cylinder, head, and sector numbers. */ u_int32_t bd_getbigeom(int bunit) { v86.ctl = V86_FLAGS; v86.addr = 0x13; v86.eax = 0x800; v86.edx = 0x80 + bunit; v86int(); if (V86_CY(v86.efl)) return 0x4f010f; return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | (v86.edx & 0xff00) | (v86.ecx & 0x3f); } /* * Return a suitable dev_t value for (dev). * * In the case where it looks like (dev) is a SCSI disk, we allow the number of * IDE disks to be specified in $num_ide_disks. There should be a Better Way. */ int bd_getdev(struct i386_devdesc *d) { struct disk_devdesc *dev; int biosdev; int major; int rootdev; char *nip, *cp; int i, unit; dev = (struct disk_devdesc *)d; biosdev = bd_unit2bios(dev->d_unit); DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev); if (biosdev == -1) /* not a BIOS device */ return(-1); if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, BD(dev).bd_sectorsize,(BD(dev).bd_flags & BD_FLOPPY) ? DISK_F_NOCACHE: 0) != 0) /* oops, not a viable device */ return (-1); else disk_close(dev); if (biosdev < 0x80) { /* floppy (or emulated floppy) or ATAPI device */ if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) { /* is an ATAPI disk */ major = WFDMAJOR; } else { /* is a floppy disk */ major = FDMAJOR; } } else { /* assume an IDE disk */ major = WDMAJOR; } /* default root disk unit number */ unit = biosdev & 0x7f; /* XXX a better kludge to set the root disk unit number */ if ((nip = getenv("root_disk_unit")) != NULL) { i = strtol(nip, &cp, 0); /* check for parse error */ if ((cp != nip) && (*cp == 0)) unit = i; } rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition); DEBUG("dev is 0x%x\n", rootdev); return(rootdev); } #ifdef LOADER_GELI_SUPPORT int bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf, size_t bytes) { struct disk_devdesc dev; dev.d_dev = &biosdisk; dev.d_type = priv->type; dev.d_unit = priv->unit; dev.d_slice = priv->slice; dev.d_partition = priv->part; dev.d_offset = priv->start; off = off / BD(&dev).bd_sectorsize; /* GELI gives us the offset relative to the partition start */ off += dev.d_offset; bytes = bytes / BD(&dev).bd_sectorsize; return (bd_io(&dev, off, bytes, buf, 0)); } #endif /* LOADER_GELI_SUPPORT */ Index: stable/11/sys/boot/i386/libi386/pxe.c =================================================================== --- stable/11/sys/boot/i386/libi386/pxe.c (revision 329009) +++ stable/11/sys/boot/i386/libi386/pxe.c (revision 329010) @@ -1,727 +1,727 @@ /*- * Copyright (c) 2000 Alfred Perlstein * Copyright (c) 2000 Paul Saab * Copyright (c) 2000 John Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "btxv86.h" #include "pxe.h" /* * Allocate the PXE buffers statically instead of sticking grimy fingers into * BTX's private data area. The scratch buffer is used to send information to * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. */ #define PXE_BUFFER_SIZE 0x2000 #define PXE_TFTP_BUFFER_SIZE 512 static char scratch_buffer[PXE_BUFFER_SIZE]; static char data_buffer[PXE_BUFFER_SIZE]; static pxenv_t *pxenv_p = NULL; /* PXENV+ */ static pxe_t *pxe_p = NULL; /* !PXE */ static BOOTPLAYER bootplayer; /* PXE Cached information. */ static int pxe_debug = 0; static int pxe_sock = -1; static int pxe_opens = 0; void pxe_enable(void *pxeinfo); static void (*pxe_call)(int func); static void pxenv_call(int func); static void bangpxe_call(int func); static int pxe_init(void); static int pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize); static int pxe_open(struct open_file *f, ...); static int pxe_close(struct open_file *f); static int pxe_print(int verbose); static void pxe_cleanup(void); static void pxe_setnfshandle(char *rootpath); static void pxe_perror(int error); static int pxe_netif_match(struct netif *nif, void *machdep_hint); static int pxe_netif_probe(struct netif *nif, void *machdep_hint); static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout); static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); static void pxe_netif_end(struct netif *nif); #ifdef OLD_NFSV2 int nfs_getrootfh(struct iodesc*, char*, u_char*); #else int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*); #endif extern struct netif_stats pxe_st[]; extern u_int16_t __bangpxeseg; extern u_int16_t __bangpxeoff; extern void __bangpxeentry(void); extern u_int16_t __pxenvseg; extern u_int16_t __pxenvoff; extern void __pxenventry(void); struct netif_dif pxe_ifs[] = { /* dif_unit dif_nsel dif_stats dif_private */ {0, 1, &pxe_st[0], 0} }; struct netif_stats pxe_st[NENTS(pxe_ifs)]; struct netif_driver pxenetif = { "pxenet", pxe_netif_match, pxe_netif_probe, pxe_netif_init, pxe_netif_get, pxe_netif_put, pxe_netif_end, pxe_ifs, NENTS(pxe_ifs) }; struct netif_driver *netif_drivers[] = { &pxenetif, NULL }; struct devsw pxedisk = { "pxe", DEVT_NET, pxe_init, pxe_strategy, pxe_open, pxe_close, noioctl, pxe_print, pxe_cleanup }; /* * This function is called by the loader to enable PXE support if we * are booted by PXE. The passed in pointer is a pointer to the * PXENV+ structure. */ void pxe_enable(void *pxeinfo) { pxenv_p = (pxenv_t *)pxeinfo; pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + pxenv_p->PXEPtr.offset); pxe_call = NULL; } /* * return true if pxe structures are found/initialized, * also figures out our IP information via the pxe cached info struct */ static int pxe_init(void) { t_PXENV_GET_CACHED_INFO *gci_p; int counter; uint8_t checksum; uint8_t *checkptr; if(pxenv_p == NULL) return (0); /* look for "PXENV+" */ if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { pxenv_p = NULL; return (0); } /* make sure the size is something we can handle */ if (pxenv_p->Length > sizeof(*pxenv_p)) { printf("PXENV+ structure too large, ignoring\n"); pxenv_p = NULL; return (0); } /* * do byte checksum: * add up each byte in the structure, the total should be 0 */ checksum = 0; checkptr = (uint8_t *) pxenv_p; for (counter = 0; counter < pxenv_p->Length; counter++) checksum += *checkptr++; if (checksum != 0) { printf("PXENV+ structure failed checksum, ignoring\n"); pxenv_p = NULL; return (0); } /* * PXENV+ passed, so use that if !PXE is not available or * the checksum fails. */ pxe_call = pxenv_call; if (pxenv_p->Version >= 0x0200) { for (;;) { if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { pxe_p = NULL; break; } checksum = 0; checkptr = (uint8_t *)pxe_p; for (counter = 0; counter < pxe_p->StructLength; counter++) checksum += *checkptr++; if (checksum != 0) { pxe_p = NULL; break; } pxe_call = bangpxe_call; break; } } printf("\nPXE version %d.%d, real mode entry point ", (uint8_t) (pxenv_p->Version >> 8), (uint8_t) (pxenv_p->Version & 0xFF)); if (pxe_call == bangpxe_call) printf("@%04x:%04x\n", pxe_p->EntryPointSP.segment, pxe_p->EntryPointSP.offset); else printf("@%04x:%04x\n", pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; bzero(gci_p, sizeof(*gci_p)); gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; pxe_call(PXENV_GET_CACHED_INFO); if (gci_p->Status != 0) { pxe_perror(gci_p->Status); pxe_p = NULL; return (0); } bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), &bootplayer, gci_p->BufferSize); return (1); } static int pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize) { return (EIO); } static int pxe_open(struct open_file *f, ...) { va_list args; char *devname; /* Device part of file name (or NULL). */ char temp[FNAME_SIZE]; int error = 0; int i; va_start(args, f); devname = va_arg(args, char*); va_end(args); /* On first open, do netif open, mount, etc. */ if (pxe_opens == 0) { /* Find network interface. */ if (pxe_sock < 0) { pxe_sock = netif_open(devname); if (pxe_sock < 0) { printf("pxe_open: netif_open() failed\n"); return (ENXIO); } if (pxe_debug) printf("pxe_open: netif_open() succeeded\n"); } if (rootip.s_addr == 0) { /* * Do a bootp/dhcp request to find out where our * NFS/TFTP server is. Even if we dont get back * the proper information, fall back to the server * which brought us to life and a default rootpath. */ bootp(pxe_sock, BOOTP_PXE); if (rootip.s_addr == 0) rootip.s_addr = bootplayer.sip; netproto = NET_NFS; if (tftpip.s_addr != 0) { netproto = NET_TFTP; rootip.s_addr = tftpip.s_addr; } if (netproto == NET_NFS && !rootpath[0]) strcpy(rootpath, PXENFSROOTPATH); for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) if (rootpath[i] == ':') break; if (i && i != FNAME_SIZE && rootpath[i] == ':') { rootpath[i++] = '\0'; if (inet_addr(&rootpath[0]) != INADDR_NONE) rootip.s_addr = inet_addr(&rootpath[0]); bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1); bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+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.netif.server", inet_ntoa(rootip), 1); if (bootplayer.Hardware == ETHER_TYPE) { sprintf(temp, "%6D", bootplayer.CAddr, ":"); setenv("boot.netif.hwaddr", temp, 1); } if (intf_mtu != 0) { char mtu[16]; sprintf(mtu, "%u", intf_mtu); setenv("boot.netif.mtu", mtu, 1); } printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); printf("pxe_open: server path: %s\n", rootpath); printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); if (netproto == NET_TFTP) { setenv("boot.tftproot.server", inet_ntoa(rootip), 1); setenv("boot.tftproot.path", rootpath, 1); } else if (netproto == NET_NFS) { setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); setenv("boot.nfsroot.path", rootpath, 1); } setenv("dhcp.host-name", hostname, 1); setenv("pxeboot.ip", inet_ntoa(myip), 1); if (bootplayer.Hardware == ETHER_TYPE) { sprintf(temp, "%6D", bootplayer.CAddr, ":"); setenv("pxeboot.hwaddr", temp, 1); } } } pxe_opens++; f->f_devdata = &pxe_sock; return (error); } static int pxe_close(struct open_file *f) { #ifdef PXE_DEBUG if (pxe_debug) printf("pxe_close: opens=%d\n", pxe_opens); #endif /* On last close, do netif close, etc. */ f->f_devdata = NULL; /* Extra close call? */ if (pxe_opens <= 0) return (0); pxe_opens--; /* Not last close? */ if (pxe_opens > 0) return(0); if (netproto == NET_NFS) { /* get an NFS filehandle for our root filesystem */ pxe_setnfshandle(rootpath); } if (pxe_sock >= 0) { #ifdef PXE_DEBUG if (pxe_debug) printf("pxe_close: calling netif_close()\n"); #endif netif_close(pxe_sock); pxe_sock = -1; } return (0); } static int pxe_print(int verbose) { char line[255]; if (pxe_call == NULL) return (0); printf("%s devices:", pxedisk.dv_name); if (pager_output("\n") != 0) return (1); if (verbose) { snprintf(line, sizeof(line), " pxe0: %s:%s\n", inet_ntoa(rootip), rootpath); } else { snprintf(line, sizeof(line), " pxe0:\n"); } return (pager_output(line)); } static void pxe_cleanup(void) { #ifdef PXE_DEBUG t_PXENV_UNLOAD_STACK *unload_stack_p = (t_PXENV_UNLOAD_STACK *)scratch_buffer; t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; #endif if (pxe_call == NULL) return; pxe_call(PXENV_UNDI_SHUTDOWN); #ifdef PXE_DEBUG if (pxe_debug && undi_shutdown_p->Status != 0) printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", undi_shutdown_p->Status); #endif pxe_call(PXENV_UNLOAD_STACK); #ifdef PXE_DEBUG if (pxe_debug && unload_stack_p->Status != 0) printf("pxe_cleanup: UNLOAD_STACK failed %x\n", unload_stack_p->Status); #endif } void pxe_perror(int err) { return; } /* * Reach inside the libstand NFS code and dig out an NFS handle * for the root filesystem. */ #ifdef OLD_NFSV2 struct nfs_iodesc { struct iodesc *iodesc; off_t off; u_char fh[NFS_FHSIZE]; /* structure truncated here */ }; extern struct nfs_iodesc nfs_root_node; extern int rpc_port; static void pxe_rpcmountcall() { struct iodesc *d; int error; if (!(d = socktodesc(pxe_sock))) return; d->myport = htons(--rpc_port); d->destip = rootip; if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0) printf("NFS MOUNT RPC error: %d\n", error); nfs_root_node.iodesc = d; } static void pxe_setnfshandle(char *rootpath) { int i; u_char *fh; char buf[2 * NFS_FHSIZE + 3], *cp; /* * If NFS files were never opened, we need to do mount call * ourselves. Use nfs_root_node.iodesc as flag indicating * previous NFS usage. */ if (nfs_root_node.iodesc == NULL) pxe_rpcmountcall(); fh = &nfs_root_node.fh[0]; buf[0] = 'X'; cp = &buf[1]; for (i = 0; i < NFS_FHSIZE; i++, cp += 2) sprintf(cp, "%02x", fh[i]); sprintf(cp, "X"); setenv("boot.nfsroot.nfshandle", buf, 1); } #else /* !OLD_NFSV2 */ #define NFS_V3MAXFHSIZE 64 struct nfs_iodesc { struct iodesc *iodesc; off_t off; uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; /* structure truncated */ }; extern struct nfs_iodesc nfs_root_node; extern int rpc_port; static void pxe_rpcmountcall() { struct iodesc *d; int error; if (!(d = socktodesc(pxe_sock))) return; d->myport = htons(--rpc_port); d->destip = rootip; if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize, nfs_root_node.fh)) != 0) { printf("NFS MOUNT RPC error: %d\n", error); nfs_root_node.fhsize = 0; } nfs_root_node.iodesc = d; } static void pxe_setnfshandle(char *rootpath) { int i; u_char *fh; char buf[2 * NFS_V3MAXFHSIZE + 3], *cp; /* * If NFS files were never opened, we need to do mount call * ourselves. Use nfs_root_node.iodesc as flag indicating * previous NFS usage. */ if (nfs_root_node.iodesc == NULL) pxe_rpcmountcall(); fh = &nfs_root_node.fh[0]; buf[0] = 'X'; cp = &buf[1]; for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) sprintf(cp, "%02x", fh[i]); sprintf(cp, "X"); setenv("boot.nfsroot.nfshandle", buf, 1); sprintf(buf, "%d", nfs_root_node.fhsize); setenv("boot.nfsroot.nfshandlelen", buf, 1); } #endif /* OLD_NFSV2 */ void pxenv_call(int func) { #ifdef PXE_DEBUG if (pxe_debug) printf("pxenv_call %x\n", func); #endif bzero(&v86, sizeof(v86)); bzero(data_buffer, sizeof(data_buffer)); __pxenvseg = pxenv_p->RMEntry.segment; __pxenvoff = pxenv_p->RMEntry.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.es = VTOPSEG(scratch_buffer); v86.edi = VTOPOFF(scratch_buffer); v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); v86.ebx = func; v86int(); v86.ctl = V86_FLAGS; } void bangpxe_call(int func) { #ifdef PXE_DEBUG if (pxe_debug) printf("bangpxe_call %x\n", func); #endif bzero(&v86, sizeof(v86)); bzero(data_buffer, sizeof(data_buffer)); __bangpxeseg = pxe_p->EntryPointSP.segment; __bangpxeoff = pxe_p->EntryPointSP.offset; v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.edx = VTOPSEG(scratch_buffer); v86.eax = VTOPOFF(scratch_buffer); v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); v86.ebx = func; v86int(); v86.ctl = V86_FLAGS; } time_t -getsecs() +getsecs(void) { time_t n = 0; time(&n); return n; } static int pxe_netif_match(struct netif *nif, void *machdep_hint) { return 1; } static int pxe_netif_probe(struct netif *nif, void *machdep_hint) { t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer; if (pxe_call == NULL) return -1; bzero(udpopen_p, sizeof(*udpopen_p)); udpopen_p->src_ip = bootplayer.yip; pxe_call(PXENV_UDP_OPEN); if (udpopen_p->status != 0) { printf("pxe_netif_probe: failed %x\n", udpopen_p->status); return -1; } return 0; } static void pxe_netif_end(struct netif *nif) { t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer; bzero(udpclose_p, sizeof(*udpclose_p)); pxe_call(PXENV_UDP_CLOSE); if (udpclose_p->status != 0) printf("pxe_end failed %x\n", udpclose_p->status); } static void pxe_netif_init(struct iodesc *desc, void *machdep_hint) { int i; for (i = 0; i < 6; ++i) desc->myea[i] = bootplayer.CAddr[i]; desc->xid = bootplayer.ident; } static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) { return len; } static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) { return len; } ssize_t sendudp(struct iodesc *h, void *pkt, size_t len) { t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; bzero(udpwrite_p, sizeof(*udpwrite_p)); udpwrite_p->ip = h->destip.s_addr; udpwrite_p->dst_port = h->destport; udpwrite_p->src_port = h->myport; udpwrite_p->buffer_size = len; udpwrite_p->buffer.segment = VTOPSEG(pkt); udpwrite_p->buffer.offset = VTOPOFF(pkt); if (netmask == 0 || SAMENET(myip, h->destip, netmask)) udpwrite_p->gw = 0; else udpwrite_p->gw = gateip.s_addr; pxe_call(PXENV_UDP_WRITE); #if 0 /* XXX - I dont know why we need this. */ delay(1000); #endif if (udpwrite_p->status != 0) { /* XXX: This happens a lot. It shouldn't. */ if (udpwrite_p->status != 1) printf("sendudp failed %x\n", udpwrite_p->status); return -1; } return len; } ssize_t readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) { t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; struct udphdr *uh = NULL; uh = (struct udphdr *) pkt - 1; bzero(udpread_p, sizeof(*udpread_p)); udpread_p->dest_ip = h->myip.s_addr; udpread_p->d_port = h->myport; udpread_p->buffer_size = len; udpread_p->buffer.segment = VTOPSEG(data_buffer); udpread_p->buffer.offset = VTOPOFF(data_buffer); pxe_call(PXENV_UDP_READ); #if 0 /* XXX - I dont know why we need this. */ delay(1000); #endif if (udpread_p->status != 0) { /* XXX: This happens a lot. It shouldn't. */ if (udpread_p->status != 1) printf("readudp failed %x\n", udpread_p->status); return -1; } bcopy(data_buffer, pkt, udpread_p->buffer_size); uh->uh_sport = udpread_p->s_port; return udpread_p->buffer_size; } Index: stable/11/sys/boot/i386/libi386/smbios.c =================================================================== --- stable/11/sys/boot/i386/libi386/smbios.c (revision 329009) +++ stable/11/sys/boot/i386/libi386/smbios.c (revision 329010) @@ -1,447 +1,453 @@ /*- * Copyright (c) 2005-2009 Jung-uk Kim * 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 #ifdef EFI /* In EFI, we don't need PTOV(). */ #define PTOV(x) (caddr_t)(x) #else #include "btxv86.h" #endif #include "smbios.h" /* * Detect SMBIOS and export information about the SMBIOS into the * environment. * * System Management BIOS Reference Specification, v2.6 Final * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf */ /* * 2.1.1 SMBIOS Structure Table Entry Point * * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can * be located by application software by searching for the anchor-string on * paragraph (16-byte) boundaries within the physical memory address range * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor * string that is used by some existing DMI browsers." */ #define SMBIOS_START 0xf0000 #define SMBIOS_LENGTH 0x10000 #define SMBIOS_STEP 0x10 #define SMBIOS_SIG "_SM_" #define SMBIOS_DMI_SIG "_DMI_" #define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) #define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) #define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) #define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) #define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) struct smbios_attr { int probed; caddr_t addr; size_t length; size_t count; int major; int minor; int ver; const char* bios_vendor; const char* maker; const char* product; uint32_t enabled_memory; uint32_t old_enabled_memory; uint8_t enabled_sockets; uint8_t populated_sockets; }; static struct smbios_attr smbios; static uint8_t smbios_checksum(const caddr_t addr, const uint8_t len) { uint8_t sum; int i; for (sum = 0, i = 0; i < len; i++) sum += SMBIOS_GET8(addr, i); return (sum); } static caddr_t smbios_sigsearch(const caddr_t addr, const uint32_t len) { caddr_t cp; /* Search on 16-byte boundaries. */ for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) if (strncmp(cp, SMBIOS_SIG, 4) == 0 && smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 && smbios_checksum(cp + 0x10, 0x0f) == 0) return (cp); return (NULL); } static const char* smbios_getstring(caddr_t addr, const int offset) { caddr_t cp; int i, idx; idx = SMBIOS_GET8(addr, offset); if (idx != 0) { cp = SMBIOS_GETSTR(addr); for (i = 1; i < idx; i++) cp += strlen(cp) + 1; return cp; } return (NULL); } static void smbios_setenv(const char *name, caddr_t addr, const int offset) { const char* val; val = smbios_getstring(addr, offset); if (val != NULL) setenv(name, val, 1); } #ifdef SMBIOS_SERIAL_NUMBERS #define UUID_SIZE 16 #define UUID_TYPE uint32_t #define UUID_STEP sizeof(UUID_TYPE) #define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) #define UUID_GET(base, off) (*(UUID_TYPE *)((base) + (off))) static void smbios_setuuid(const char *name, const caddr_t addr, const int ver) { char uuid[37]; int byteorder, i, ones, zeros; UUID_TYPE n; uint32_t f1; uint16_t f2, f3; for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { n = UUID_GET(addr, i) + 1; if (zeros == 0 && n == 0) ones++; else if (ones == 0 && n == 1) zeros++; else break; } if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { /* * 3.3.2.1 System UUID * * "Although RFC 4122 recommends network byte order for all * fields, the PC industry (including the ACPI, UEFI, and * Microsoft specifications) has consistently used * little-endian byte encoding for the first three fields: * time_low, time_mid, time_hi_and_version. The same encoding, * also known as wire format, should also be used for the * SMBIOS representation of the UUID." * * Note: We use network byte order for backward compatibility * unless SMBIOS version is 2.6+ or little-endian is forced. */ #if defined(SMBIOS_LITTLE_ENDIAN_UUID) byteorder = LITTLE_ENDIAN; #elif defined(SMBIOS_NETWORK_ENDIAN_UUID) byteorder = BIG_ENDIAN; #else byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; #endif if (byteorder != LITTLE_ENDIAN) { f1 = ntohl(SMBIOS_GET32(addr, 0)); f2 = ntohs(SMBIOS_GET16(addr, 4)); f3 = ntohs(SMBIOS_GET16(addr, 6)); } else { f1 = le32toh(SMBIOS_GET32(addr, 0)); f2 = le16toh(SMBIOS_GET16(addr, 4)); f3 = le16toh(SMBIOS_GET16(addr, 6)); } sprintf(uuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); setenv(name, uuid, 1); } } #undef UUID_SIZE #undef UUID_TYPE #undef UUID_STEP #undef UUID_ALL_BITS #undef UUID_GET #endif static caddr_t smbios_parse_table(const caddr_t addr) { caddr_t cp; int proc, size, osize, type; type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ switch(type) { case 0: /* 3.3.1 BIOS Information (Type 0) */ smbios_setenv("smbios.bios.vendor", addr, 0x04); smbios_setenv("smbios.bios.version", addr, 0x05); smbios_setenv("smbios.bios.reldate", addr, 0x08); break; case 1: /* 3.3.2 System Information (Type 1) */ smbios_setenv("smbios.system.maker", addr, 0x04); smbios_setenv("smbios.system.product", addr, 0x05); smbios_setenv("smbios.system.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.system.serial", addr, 0x07); smbios_setuuid("smbios.system.uuid", addr + 0x08, smbios.ver); #endif + if (smbios.major >= 2 && smbios.minor >= 4) { + smbios_setenv("smbios.system.sku", addr, 0x19); + smbios_setenv("smbios.system.family", addr, 0x1a); + } break; case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ smbios_setenv("smbios.planar.maker", addr, 0x04); smbios_setenv("smbios.planar.product", addr, 0x05); smbios_setenv("smbios.planar.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.planar.serial", addr, 0x07); + smbios_setenv("smbios.planar.tag", addr, 0x08); #endif + smbios_setenv("smbios.planar.location", addr, 0x0a); break; case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ smbios_setenv("smbios.chassis.maker", addr, 0x04); smbios_setenv("smbios.chassis.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.chassis.serial", addr, 0x07); smbios_setenv("smbios.chassis.tag", addr, 0x08); #endif break; case 4: /* 3.3.5 Processor Information (Type 4) */ /* * Offset 18h: Processor Status * * Bit 7 Reserved, must be 0 * Bit 6 CPU Socket Populated * 1 - CPU Socket Populated * 0 - CPU Socket Unpopulated * Bit 5:3 Reserved, must be zero * Bit 2:0 CPU Status * 0h - Unknown * 1h - CPU Enabled * 2h - CPU Disabled by User via BIOS Setup * 3h - CPU Disabled by BIOS (POST Error) * 4h - CPU is Idle, waiting to be enabled * 5-6h - Reserved * 7h - Other */ proc = SMBIOS_GET8(addr, 0x18); if ((proc & 0x07) == 1) smbios.enabled_sockets++; if ((proc & 0x40) != 0) smbios.populated_sockets++; break; case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ /* * Offset 0Ah: Enabled Size * * Bit 7 Bank connection * 1 - Double-bank connection * 0 - Single-bank connection * Bit 6:0 Size (n), where 2**n is the size in MB * 7Dh - Not determinable (Installed Size only) * 7Eh - Module is installed, but no memory * has been enabled * 7Fh - Not installed */ osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; if (osize > 0 && osize < 22) smbios.old_enabled_memory += 1 << (osize + 10); break; case 17: /* 3.3.18 Memory Device (Type 17) */ /* * Offset 0Ch: Size * * Bit 15 Granularity * 1 - Value is in kilobytes units * 0 - Value is in megabytes units * Bit 14:0 Size */ size = SMBIOS_GET16(addr, 0x0c); if (size != 0 && size != 0xffff) smbios.enabled_memory += (size & 0x8000) != 0 ? (size & 0x7fff) : (size << 10); break; default: /* skip other types */ break; } /* Find structure terminator. */ cp = SMBIOS_GETSTR(addr); while (SMBIOS_GET16(cp, 0) != 0) cp++; return (cp + 2); } static caddr_t smbios_find_struct(int type) { caddr_t dmi; size_t i; if (smbios.addr == NULL) return (NULL); for (dmi = smbios.addr, i = 0; dmi < smbios.addr + smbios.length && i < smbios.count; i++) { if (SMBIOS_GET8(dmi, 0) == type) return dmi; /* Find structure terminator. */ dmi = SMBIOS_GETSTR(dmi); while (SMBIOS_GET16(dmi, 0) != 0) dmi++; dmi += 2; } return (NULL); } static void smbios_probe(const caddr_t addr) { caddr_t saddr, info; uintptr_t paddr; if (smbios.probed) return; smbios.probed = 1; /* Search signatures and validate checksums. */ saddr = smbios_sigsearch(addr ? addr : PTOV(SMBIOS_START), SMBIOS_LENGTH); if (saddr == NULL) return; smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ if (smbios.ver != 0) { smbios.major = smbios.ver >> 4; smbios.minor = smbios.ver & 0x0f; if (smbios.major > 9 || smbios.minor > 9) smbios.ver = 0; } if (smbios.ver == 0) { smbios.major = SMBIOS_GET8(saddr, 0x06);/* SMBIOS Major Version */ smbios.minor = SMBIOS_GET8(saddr, 0x07);/* SMBIOS Minor Version */ } smbios.ver = (smbios.major << 8) | smbios.minor; smbios.addr = PTOV(paddr); /* Get system information from SMBIOS */ info = smbios_find_struct(0x00); if (info != NULL) { smbios.bios_vendor = smbios_getstring(info, 0x04); } info = smbios_find_struct(0x01); if (info != NULL) { smbios.maker = smbios_getstring(info, 0x04); smbios.product = smbios_getstring(info, 0x05); } } void smbios_detect(const caddr_t addr) { char buf[16]; caddr_t dmi; size_t i; smbios_probe(addr); if (smbios.addr == NULL) return; for (dmi = smbios.addr, i = 0; dmi < smbios.addr + smbios.length && i < smbios.count; i++) dmi = smbios_parse_table(dmi); sprintf(buf, "%d.%d", smbios.major, smbios.minor); setenv("smbios.version", buf, 1); if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { sprintf(buf, "%u", smbios.enabled_memory > 0 ? smbios.enabled_memory : smbios.old_enabled_memory); setenv("smbios.memory.enabled", buf, 1); } if (smbios.enabled_sockets > 0) { sprintf(buf, "%u", smbios.enabled_sockets); setenv("smbios.socket.enabled", buf, 1); } if (smbios.populated_sockets > 0) { sprintf(buf, "%u", smbios.populated_sockets); setenv("smbios.socket.populated", buf, 1); } } static int smbios_match_str(const char* s1, const char* s2) { return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); } int smbios_match(const char* bios_vendor, const char* maker, const char* product) { /* XXXRP currently, only called from non-EFI. */ smbios_probe(NULL); return (smbios_match_str(bios_vendor, smbios.bios_vendor) && smbios_match_str(maker, smbios.maker) && smbios_match_str(product, smbios.product)); } Index: stable/11/sys/boot/i386/mbr/Makefile =================================================================== --- stable/11/sys/boot/i386/mbr/Makefile (revision 329009) +++ stable/11/sys/boot/i386/mbr/Makefile (revision 329010) @@ -1,17 +1,17 @@ # $FreeBSD$ PROG= mbr STRIP= BINMODE=${NOBINMODE} MAN= SRCS= ${PROG}.s # MBR flags: 0x80 -- try packet interface (also known as EDD or LBA) BOOT_MBR_FLAGS?= 0x80 ORG= 0x600 AFLAGS+=--defsym FLAGS=${BOOT_MBR_FLAGS} -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include Index: stable/11/sys/boot/i386/pmbr/Makefile =================================================================== --- stable/11/sys/boot/i386/pmbr/Makefile (revision 329009) +++ stable/11/sys/boot/i386/pmbr/Makefile (revision 329010) @@ -1,14 +1,14 @@ # $FreeBSD$ PROG= pmbr STRIP= BINMODE=${NOBINMODE} MAN= SRCS= ${PROG}.s ORG= 0x600 AFLAGS+=--defsym FLAGS=${BOOT_MBR_FLAGS} -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include Index: stable/11/sys/boot/i386/pxeldr/Makefile =================================================================== --- stable/11/sys/boot/i386/pxeldr/Makefile (revision 329009) +++ stable/11/sys/boot/i386/pxeldr/Makefile (revision 329010) @@ -1,48 +1,48 @@ # $FreeBSD$ # Pick up ../Makefile.inc early. .include PROG= ${LDR} INTERNALPROG= FILES= ${BOOT} MAN= ${BOOT}.8 SRCS= ${LDR}.S CLEANFILES= ${BOOT} BOOT= pxeboot LDR= pxeldr ORG= 0x7c00 LOADER= loader .if defined(BOOT_PXELDR_PROBE_KEYBOARD) CFLAGS+=-DPROBE_KEYBOARD .endif .if defined(BOOT_PXELDR_ALWAYS_SERIAL) CFLAGS+=-DALWAYS_SERIAL .endif CFLAGS+=-I${.CURDIR}/../common LOADERBIN= ${.OBJDIR}/../loader/loader.bin CLEANFILES+= ${BOOT}.tmp ${BOOT}: ${LDR} ${LOADER} cat ${LDR} ${LOADER} > ${.TARGET}.tmp ${DD} if=${.TARGET}.tmp of=${.TARGET} obs=2k conv=osync rm ${.TARGET}.tmp -LDFLAGS+=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS+=${LDFLAGS_BIN} CLEANFILES+= ${LOADER} ${LOADER}: ${LOADERBIN} ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ -b ${BTXKERN} ${LOADERBIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.pxeldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/i386/zfsboot/Makefile =================================================================== --- stable/11/sys/boot/i386/zfsboot/Makefile (revision 329009) +++ stable/11/sys/boot/i386/zfsboot/Makefile (revision 329010) @@ -1,100 +1,100 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common \ ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein FILES= zfsboot MAN= zfsboot.8 NM?= nm BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x2000 CFLAGS= -DBOOTPROG=\"zfsboot\" \ -O1 \ -DZFS -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ -I${.CURDIR}/../../../crypto/skein \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline CFLAGS.gcc+= --param max-inline-insns-single=100 # Do not unroll skein loops, reduce code size CFLAGS+= -DSKEIN_LOOP=111 -LD_FLAGS=-static -N --gc-sections +LD_FLAGS=${LD_FLAGS_BIN} LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a # Pick up ../Makefile.inc early. .include CLEANFILES= zfsboot zfsboot: zfsboot1 zfsboot2 cat zfsboot1 zfsboot2 > zfsboot CLEANFILES+= zfsboot1 zfsldr.out zfsldr.o zfsboot1: zfsldr.out ${OBJCOPY} -S -O binary zfsldr.out ${.TARGET} zfsldr.out: zfsldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \ zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o util.o \ skein.o skein_block.o # We currently allow 128k bytes for zfsboot - in practice it could be # any size up to 3.5Mb but keeping it fixed size simplifies zfsldr. # BOOT2SIZE= 131072 zfsboot2: zfsboot.ld @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \ echo "$$x bytes available"; test $$x -ge 0 ${DD} if=${.ALLSRC} of=${.TARGET} obs=${BOOT2SIZE} conv=osync zfsboot.ld: zfsboot.ldr zfsboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l zfsboot.ldr \ -o ${.TARGET} -P 1 zfsboot.bin zfsboot.ldr: cp /dev/null ${.TARGET} zfsboot.bin: zfsboot.out ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET} zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o skein.o skein_block.o ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} SRCS= zfsboot.c .if ${MACHINE_CPUARCH} == "amd64" beforedepend zfsboot.o: machine CLEANFILES+= machine machine: .NOMETA ln -sf ${.CURDIR}/../../../i386/include machine .endif .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.zfsldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/ofw/libofw/ofw_time.c =================================================================== --- stable/11/sys/boot/ofw/libofw/ofw_time.c (revision 329009) +++ stable/11/sys/boot/ofw/libofw/ofw_time.c (revision 329010) @@ -1,61 +1,61 @@ /*- * Copyright (c) 2000 Benno Rice * 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 Benno Rice ``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 REGENTS 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" time_t time(time_t *tloc) { int secs; secs = OF_milliseconds() / 1000; if (tloc) *tloc = secs; return secs; } -int -getsecs() +time_t +getsecs(void) { time_t n = 0; time(&n); return n; } void delay(int usecs) { int msecs, start; msecs = usecs / 1000; start = OF_milliseconds(); while (OF_milliseconds() - start < msecs); } Index: stable/11/sys/boot/pc98/Makefile.inc =================================================================== --- stable/11/sys/boot/pc98/Makefile.inc (revision 329009) +++ stable/11/sys/boot/pc98/Makefile.inc (revision 329010) @@ -1,24 +1,29 @@ # Common defines for all of /sys/boot/pc98/ # # $FreeBSD$ BINDIR?= /boot LOADER_ADDRESS?=0x200000 CFLAGS+= -march=i386 -ffreestanding CFLAGS.gcc+= -mpreferred-stack-boundary=2 CFLAGS+= ${CFLAGS_NO_SIMD} -msoft-float CFLAGS+= -Os -DPC98 LDFLAGS+= -nostdlib # BTX components .if exists(${.OBJDIR}/../btx) BTXDIR= ${.OBJDIR}/../btx .else BTXDIR= ${.CURDIR}/../btx .endif BTXLDR= ${BTXDIR}/btxldr/btxldr BTXKERN= ${BTXDIR}/btx/btx BTXCRT= ${BTXDIR}/lib/crt0.o +# compact binary with no padding between text, data, bss +LDSCRIPT= ${SRCTOP}/sys/boot/i386/boot.ldscript +LDFLAGS_BIN=-e start -Ttext ${ORG} -Wl,-T,${LDSCRIPT},-S,--oformat,binary +LD_FLAGS_BIN=-static -T ${LDSCRIPT} --gc-sections + .include "../Makefile.inc" Index: stable/11/sys/boot/pc98/boot0/Makefile =================================================================== --- stable/11/sys/boot/pc98/boot0/Makefile (revision 329009) +++ stable/11/sys/boot/pc98/boot0/Makefile (revision 329010) @@ -1,21 +1,19 @@ # $FreeBSD$ -PROG= ${BOOT}.out +PROG= ${BOOT} INTERNALPROG= FILES= ${BOOT} MAN= SRCS= ${BOOT}.s CLEANFILES= ${BOOT} BOOT= boot0 # The base address that we the boot0 code to to run it. Don't change this # unless you are glutton for punishment. BOOT_BOOT0_ORG?= 0x0000 +ORG=${BOOT_BOOT0_ORG} -LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} -Wl,-N - -${BOOT}: ${BOOT}.out - ${OBJCOPY} -S -O binary ${BOOT}.out ${.TARGET} +LDFLAGS=${LDFLAGS_BIN} .include Index: stable/11/sys/boot/pc98/boot2/Makefile =================================================================== --- stable/11/sys/boot/pc98/boot2/Makefile (revision 329009) +++ stable/11/sys/boot/pc98/boot2/Makefile (revision 329010) @@ -1,116 +1,116 @@ # $FreeBSD$ .include FILES= boot boot1 boot2 NM?= nm BOOT_COMCONSOLE_PORT?= 0x238 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0 ORG2= 0x2000 # Decide level of UFS support. BOOT2_UFS?= UFS1_AND_UFS2 #BOOT2_UFS?= UFS2_ONLY #BOOT2_UFS?= UFS1_ONLY CFLAGS= -fomit-frame-pointer \ -mrtd \ -mregparm=3 \ -D${BOOT2_UFS} \ -DFLAGS=${BOOT_BOOT1_FLAGS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../.. \ -I${.CURDIR}/../../i386/boot2 \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../btx/lib -I. \ -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline CFLAGS.gcc+= -Os \ -fno-guess-branch-probability \ -fno-unit-at-a-time \ --param max-inline-insns-single=100 .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} <= 40201 CFLAGS.gcc+= -mno-align-long-strings .endif # Set machine type to PC98_SYSTEM_PARAMETER #CFLAGS+= -DSET_MACHINE_TYPE # Initialize the bi_bios_geom using the BIOS geometry #CFLAGS+= -DGET_BIOSGEOM CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL} -LD_FLAGS=-static -N --gc-sections +LD_FLAGS=${LD_FLAGS_BIN} # Pick up ../Makefile.inc early. .include .PATH: ${.CURDIR}/../../i386/boot2 CLEANFILES= boot boot: boot1 boot2 cat boot1 boot2 > boot CLEANFILES+= boot1 boot1.out boot1.o boot1: boot1.out ${OBJCOPY} -S -O binary boot1.out ${.TARGET} boot1.out: boot1.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o CLEANFILES+= boot2 boot2.ld boot2.ldr boot2.bin boot2.out boot2.o \ boot2.s boot2.s.tmp boot2.h sio.o boot2: boot2.ld @set -- `ls -l boot2.ld`; x=$$((7680-$$5)); \ echo "$$x bytes available"; test $$x -ge 0 ${DD} if=boot2.ld of=${.TARGET} obs=7680 conv=osync boot2.ld: boot2.ldr boot2.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l boot2.ldr \ -o ${.TARGET} -P 1 boot2.bin boot2.ldr: ${DD} if=/dev/zero of=${.TARGET} bs=276 count=1 boot2.bin: boot2.out ${OBJCOPY} -S -O binary boot2.out ${.TARGET} boot2.out: ${BTXCRT} boot2.o sio.o ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} boot2.o: boot2.s ${CC} ${ACFLAGS} -c boot2.s SRCS= boot2.c boot2.h boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c ${CC} ${CFLAGS} -S -o boot2.s.tmp ${.CURDIR}/boot2.c sed -e '/align/d' -e '/nop/d' < boot2.s.tmp > boot2.s rm -f boot2.s.tmp boot2.h: boot1.out ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T (read|putc)/ \ { x = $$1 - ORG1; \ printf("#define %sORG %#x\n", toupper($$3), REL1 + x) }' \ ORG1=`printf "%d" ${ORG1}` \ REL1=`printf "%d" ${REL1}` > ${.TARGET} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.boot1.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/pc98/btx/btx/Makefile =================================================================== --- stable/11/sys/boot/pc98/btx/btx/Makefile (revision 329009) +++ stable/11/sys/boot/pc98/btx/btx/Makefile (revision 329010) @@ -1,33 +1,33 @@ # $FreeBSD$ PROG= btx INTERNALPROG= MAN= SRCS= btx.S .if defined(BOOT_BTX_NOHANG) BOOT_BTX_FLAGS=0x1 .else BOOT_BTX_FLAGS=0x0 .endif CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} CFLAGS+=-I${.CURDIR}/../../../i386/common .if defined(BTX_SERIAL) BOOT_COMCONSOLE_PORT?= 0x238 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} .endif ORG= 0x9000 -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btx.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/pc98/btx/btxldr/Makefile =================================================================== --- stable/11/sys/boot/pc98/btx/btxldr/Makefile (revision 329009) +++ stable/11/sys/boot/pc98/btx/btxldr/Makefile (revision 329010) @@ -1,20 +1,21 @@ # $FreeBSD$ PROG= btxldr INTERNALPROG= MAN= SRCS= btxldr.S CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} CFLAGS+=-I${.CURDIR}/../../../i386/common .if defined(BTXLDR_VERBOSE) CFLAGS+=-DBTXLDR_VERBOSE .endif -LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -Wl,-N,-S,--oformat,binary +ORG=${LOADER_ADDRESS} +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.btxldr.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/pc98/cdboot/Makefile =================================================================== --- stable/11/sys/boot/pc98/cdboot/Makefile (revision 329009) +++ stable/11/sys/boot/pc98/cdboot/Makefile (revision 329010) @@ -1,18 +1,18 @@ # $FreeBSD$ PROG= cdboot STRIP= BINMODE=${NOBINMODE} MAN= SRCS= ${PROG}.S CFLAGS+=-I${.CURDIR}/../../i386/common ORG= 0x0000 -LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary +LDFLAGS=${LDFLAGS_BIN} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.cdboot.S= ${CLANG_NO_IAS} Index: stable/11/sys/boot/powerpc/kboot/main.c =================================================================== --- stable/11/sys/boot/powerpc/kboot/main.c (revision 329009) +++ stable/11/sys/boot/powerpc/kboot/main.c (revision 329010) @@ -1,319 +1,319 @@ /*- * 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 #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); extern int command_fdt_internal(int argc, char *argv[]); 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 = argv[1]; /* * 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(); 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; printf("\n%s", bootprog_info); setenv("currdev", bootdev, 1); setenv("loaddev", bootdev, 1); setenv("LINES", "24", 1); interact(NULL); /* doesn't return */ return (0); } void exit(int code) { /* XXX: host_exit */ } 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); } -int -getsecs() +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 = 2*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) { /* * Need to stay out of the way of Linux. /chosen/linux,kernel-end does * a better job here, but use a fixed offset for now. */ if (type == LOAD_ELF) addr = roundup(addr, PAGE_SIZE); else addr += 64*1024*1024; /* Stay out of the way of Linux */ return (addr); } 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/sys/boot/powerpc/ps3/main.c =================================================================== --- stable/11/sys/boot/powerpc/ps3/main.c (revision 329009) +++ stable/11/sys/boot/powerpc/ps3/main.c (revision 329010) @@ -1,248 +1,248 @@ /*- * Copyright (C) 2010 Nathan Whitehorn * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) * 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 #define _KERNEL #include #include "bootstrap.h" #include "lv1call.h" #include "ps3.h" #include "ps3devdesc.h" struct arch_switch archsw; extern void *_end; extern char bootprog_info[]; int ps3_getdev(void **vdev, const char *devspec, const char **path); ssize_t ps3_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t ps3_copyout(vm_offset_t src, void *dest, const size_t len); ssize_t ps3_readin(const int fd, vm_offset_t dest, const size_t len); int ps3_autoload(void); int ps3_setcurrdev(struct env_var *ev, int flags, const void *value); static uint64_t basetb; int main(void) { uint64_t maxmem = 0; void *heapbase; int i, err; struct ps3_devdesc currdev; struct open_file f; lv1_get_physmem(&maxmem); ps3mmu_init(maxmem); /* * Set up console. */ cons_probe(); /* * Set the heap to one page after the end of the loader. */ heapbase = (void *)(maxmem - 0x80000); setheap(heapbase, maxmem); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_init != NULL) { err = (devsw[i]->dv_init)(); if (err) { printf("\n%s: initialization failed err=%d\n", devsw[i]->dv_name, err); continue; } } currdev.d_dev = devsw[i]; currdev.d_type = currdev.d_dev->dv_type; if (strcmp(devsw[i]->dv_name, "cd") == 0) { f.f_devdata = &currdev; currdev.d_unit = 0; if (devsw[i]->dv_open(&f, &currdev) == 0) break; } if (strcmp(devsw[i]->dv_name, "disk") == 0) { f.f_devdata = &currdev; currdev.d_unit = 3; currdev.d_disk.pnum = 1; currdev.d_disk.ptype = PTYPE_GPT; if (devsw[i]->dv_open(&f, &currdev) == 0) break; } if (strcmp(devsw[i]->dv_name, "net") == 0) break; } if (devsw[i] == NULL) panic("No boot device found!"); else printf("Boot device: %s\n", devsw[i]->dv_name); /* * Get timebase at boot. */ basetb = mftb(); archsw.arch_getdev = ps3_getdev; archsw.arch_copyin = ps3_copyin; archsw.arch_copyout = ps3_copyout; archsw.arch_readin = ps3_readin; archsw.arch_autoload = ps3_autoload; printf("\n%s", bootprog_info); printf("Memory: %lldKB\n", maxmem / 1024); env_setenv("currdev", EV_VOLATILE, ps3_fmtdev(&currdev), ps3_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, ps3_fmtdev(&currdev), env_noset, env_nounset); setenv("LINES", "24", 1); setenv("hw.platform", "ps3", 1); interact(NULL); /* doesn't return */ return (0); } void ppc_exception(int code, vm_offset_t where, register_t msr) { mtmsr(PSL_IR | PSL_DR | PSL_RI); printf("Exception %x at %#lx!\n", code, where); printf("Rebooting in 5 seconds...\n"); delay(10000000); lv1_panic(1); } const u_int ns_per_tick = 12; void exit(int code) { lv1_panic(code); } void delay(int usecs) { uint64_t tb,ttb; tb = mftb(); ttb = tb + howmany(usecs * 1000, ns_per_tick); while (tb < ttb) tb = mftb(); } -int -getsecs() +time_t +getsecs(void) { - return ((mftb() - basetb)*ns_per_tick/1000000000); + return ((time_t)((mftb() - basetb)*ns_per_tick/1000000000)); } time_t time(time_t *tloc) { time_t rv; rv = getsecs(); if (tloc != NULL) *tloc = rv; return (rv); } ssize_t ps3_copyin(const void *src, vm_offset_t dest, const size_t len) { bcopy(src, (void *)dest, len); return (len); } ssize_t ps3_copyout(vm_offset_t src, void *dest, const size_t len) { bcopy((void *)src, dest, len); return (len); } ssize_t ps3_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("ps3_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("ps3_readin: read failed\n"); break; } bcopy(buf, (void *)p, got); } free(buf); return (len - resid); } int ps3_autoload(void) { return (0); } Index: stable/11/sys/boot/uboot/lib/time.c =================================================================== --- stable/11/sys/boot/uboot/lib/time.c (revision 329009) +++ stable/11/sys/boot/uboot/lib/time.c (revision 329010) @@ -1,65 +1,65 @@ /*- * Copyright (c) 2000 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 "glue.h" /* * Return the time in seconds since the beginning of the day. */ time_t time(time_t *tloc) { int secs; secs = ub_get_timer(0) / 1000; if (tloc) *tloc = secs; return (secs); } -int +time_t getsecs(void) { return (time(NULL)); } /* * Use U-Boot udelay() function to wait for a given microseconds period */ void delay(int usecs) { ub_udelay(usecs); } Index: stable/11 =================================================================== --- stable/11 (revision 329009) +++ stable/11 (revision 329010) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r303555-303556,303936,303962,304317,304532,305026,305107,305132,305178,305353,305814,306159,306380,306504