diff options
Diffstat (limited to 'stand')
162 files changed, 2567 insertions, 1753 deletions
diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h index 0c6462f8d1a1..17887919089c 100644 --- a/stand/common/bootstrap.h +++ b/stand/common/bootstrap.h @@ -326,7 +326,8 @@ 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. + * actual configuration of the target system, though some routines are + * mandatory. */ struct arch_switch { @@ -351,14 +352,6 @@ struct arch_switch 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. */ @@ -379,6 +372,8 @@ extern struct arch_switch archsw; /* This must be provided by the MD code, but should it be in the archsw? */ void delay(int delay); +int setprint_delay(struct env_var *ev, int flags, const void *value); + /* common code to set currdev variable. */ int gen_setcurrdev(struct env_var *ev, int flags, const void *value); int mount_currdev(struct env_var *, int, const void *); diff --git a/stand/common/commands.c b/stand/common/commands.c index 95d12ad95973..19452047a0ca 100644 --- a/stand/common/commands.c +++ b/stand/common/commands.c @@ -291,6 +291,63 @@ command_show(int argc, char *argv[]) return (CMD_OK); } +#ifdef LOADER_VERIEXEC +static int +is_restricted_var(const char *var) +{ + /* + * We impose restrictions if input is not verified + * allowing for exceptions. + * These entries should include the '=' + */ + const char *allowed[] = { + "boot_function=", + "boot_phase=", + "boot_recover_cli=", + "boot_recover_volume=", + "boot_safe=", + "boot_set=", + "boot_single=", + "boot_verbose=", + NULL, + }; + const char *restricted[] = { + "boot", + "init", + "loader.ve.", + "rootfs", + "secur", + "vfs.", + NULL, + }; + const char **cp; + int ok = -1; + +#ifdef LOADER_VERIEXEC_TESTING + printf("Checking: %s\n", var); +#endif + for (cp = restricted; *cp; cp++) { + if (strncmp(var, *cp, strlen(*cp)) == 0) { + ok = 0; + break; + } + } + if (!ok) { + /* + * Check for exceptions. + * These should match up to '='. + */ + for (cp = allowed; *cp; cp++) { + if (strncmp(var, *cp, strlen(*cp)) == 0) { + ok = 1; + break; + } + } + } + return (ok == 0); +} +#endif + COMMAND_SET(set, "set", "set a variable", command_set); static int @@ -303,32 +360,14 @@ command_set(int argc, char *argv[]) return (CMD_ERROR); } else { #ifdef LOADER_VERIEXEC - /* - * Impose restrictions if input is not verified - */ - const char *restricted[] = { - "boot", - "init", - "loader.ve.", - "rootfs", - "secur", - "vfs.", - NULL, - }; - const char **cp; int ves; ves = ve_status_get(-1); if (ves == VE_UNVERIFIED_OK) { -#ifdef LOADER_VERIEXEC_TESTING - printf("Checking: %s\n", argv[1]); -#endif - for (cp = restricted; *cp; cp++) { - if (strncmp(argv[1], *cp, strlen(*cp)) == 0) { - printf("Ignoring restricted variable: %s\n", - argv[1]); - return (CMD_OK); - } + if (is_restricted_var(argv[1])) { + printf("Ignoring restricted variable: %s\n", + argv[1]); + return (CMD_OK); } } #endif @@ -351,6 +390,18 @@ command_unset(int argc, char *argv[]) command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } else { +#ifdef LOADER_VERIEXEC + int ves; + + ves = ve_status_get(-1); + if (ves == VE_UNVERIFIED_OK) { + if (is_restricted_var(argv[1])) { + printf("Ignoring restricted variable: %s\n", + argv[1]); + return (CMD_OK); + } + } +#endif if ((err = unsetenv(argv[1])) != 0) { command_errmsg = strerror(err); return (CMD_ERROR); diff --git a/stand/common/console.c b/stand/common/console.c index 82cb552b4ef2..65ab7ffad622 100644 --- a/stand/common/console.c +++ b/stand/common/console.c @@ -44,6 +44,8 @@ static int twiddle_set(struct env_var *ev, int flags, const void *value); #endif int module_verbose = MODULE_VERBOSE; +static uint32_t print_delay_usec = 0; + static int module_verbose_set(struct env_var *ev, int flags, const void *value) { @@ -66,6 +68,23 @@ module_verbose_set(struct env_var *ev, int flags, const void *value) } /* + * Hook to set the print delay + */ +int +setprint_delay(struct env_var *ev, int flags, const void *value) +{ + char *end; + int usec = strtol(value, &end, 10); + + if (*(char *)value == '\0' || *end != '\0') + return (EINVAL); + if (usec < 0) + return (EINVAL); + print_delay_usec = usec; + return (0); +} + +/* * Detect possible console(s) to use. If preferred console(s) have been * specified, mark them as active. Else, mark the first probed console * as active. Also create the console variable. @@ -178,6 +197,10 @@ putchar(int c) (C_PRESENTOUT | C_ACTIVEOUT)) consoles[cons]->c_out(c); } + + /* Pause after printing newline character if a print delay is set */ + if (print_delay_usec != 0 && c == '\n') + delay(print_delay_usec); } /* diff --git a/stand/common/dev_net.c b/stand/common/dev_net.c index 3cd78c5346ac..d1c48d40691a 100644 --- a/stand/common/dev_net.c +++ b/stand/common/dev_net.c @@ -47,9 +47,10 @@ * for use by the NFS open code (NFS/lookup). */ -#include <machine/stdarg.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/stdarg.h> + #include <net/if.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -65,8 +66,8 @@ #include "dev_net.h" #include "bootstrap.h" -#ifdef NETIF_DEBUG -int debug = 0; +#ifndef NETPROTO_DEFAULT +# define NETPROTO_DEFAULT NET_NFS #endif static char *netdev_name; @@ -142,11 +143,8 @@ net_open(struct open_file *f, ...) return (ENXIO); } netdev_name = strdup(devname); -#ifdef NETIF_DEBUG - if (debug) - printf("%s: netif_open() succeeded\n", - __func__); -#endif + DEBUG_PRINTF(1,("%s: netif_open() succeeded %#x\n", + __func__, rootip.s_addr)); } /* * If network params were not set by netif_open(), try to get @@ -188,6 +186,7 @@ net_open(struct open_file *f, ...) setenv("boot.netif.mtu", mtu, 1); } + DEBUG_PRINTF(1,("%s: netproto=%d\n", __func__, netproto)); } netdev_opens++; dev->d_opendata = &netdev_sock; @@ -199,10 +198,7 @@ net_close(struct open_file *f) { struct devdesc *dev; -#ifdef NETIF_DEBUG - if (debug) - printf("%s: opens=%d\n", __func__, netdev_opens); -#endif + DEBUG_PRINTF(2,("%s: opens=%d\n", __func__, netdev_opens)); dev = f->f_devdata; dev->d_opendata = NULL; @@ -215,10 +211,7 @@ net_cleanup(void) { if (netdev_sock >= 0) { -#ifdef NETIF_DEBUG - if (debug) - printf("%s: calling netif_close()\n", __func__); -#endif + DEBUG_PRINTF(1,("%s: calling netif_close()\n", __func__)); rootip.s_addr = 0; free(netdev_name); netif_close(netdev_sock); @@ -270,10 +263,7 @@ net_getparams(int sock) bootp(sock); if (myip.s_addr != 0) goto exit; -#ifdef NETIF_DEBUG - if (debug) - printf("%s: BOOTP failed, trying RARP/RPC...\n", __func__); -#endif + DEBUG_PRINTF(1,("%s: BOOTP failed, trying RARP/RPC...\n", __func__)); #endif /* @@ -291,10 +281,7 @@ net_getparams(int sock) printf("%s: bootparam/whoami RPC failed\n", __func__); return (EIO); } -#ifdef NETIF_DEBUG - if (debug) - printf("%s: client name: %s\n", __func__, hostname); -#endif + DEBUG_PRINTF(1,("%s: client name: %s\n", __func__, hostname)); /* * Ignore the gateway from whoami (unreliable). @@ -308,16 +295,12 @@ net_getparams(int sock) } if (smask) { netmask = smask; -#ifdef NETIF_DEBUG - if (debug) - printf("%s: subnet mask: %s\n", __func__, - intoa(netmask)); -#endif + DEBUG_PRINTF(1,("%s: subnet mask: %s\n", __func__, + intoa(netmask))); } -#ifdef NETIF_DEBUG - if (gateip.s_addr && debug) - printf("%s: net gateway: %s\n", __func__, inet_ntoa(gateip)); -#endif + if (gateip.s_addr) + DEBUG_PRINTF(1,("%s: net gateway: %s\n", __func__, + inet_ntoa(gateip))); /* Get the root server and pathname. */ if (bp_getfile(sock, "root", &rootip, rootpath)) { @@ -325,15 +308,13 @@ net_getparams(int sock) return (EIO); } exit: - if ((rootaddr = net_parse_rootpath()) != INADDR_NONE) + if ((rootaddr = net_parse_rootpath()) != htonl(INADDR_NONE)) rootip.s_addr = rootaddr; -#ifdef NETIF_DEBUG - if (debug) { - printf("%s: server addr: %s\n", __func__, inet_ntoa(rootip)); - printf("%s: server path: %s\n", __func__, rootpath); - } -#endif + DEBUG_PRINTF(1,("%s: proto: %d\n", __func__, netproto)); + DEBUG_PRINTF(1,("%s: server addr: %s\n", __func__, inet_ntoa(rootip))); + DEBUG_PRINTF(1,("%s: server port: %d\n", __func__, rootport)); + DEBUG_PRINTF(1,("%s: server path: %s\n", __func__, rootpath)); return (0); } @@ -368,11 +349,17 @@ net_print(int verbose) return (ret); } +bool +is_tftp(void) +{ + return (netproto == NET_TFTP); +} + /* * Parses the rootpath if present * * The rootpath format can be in the form - * <scheme>://ip/path + * <scheme>://ip[:port]/path * <scheme>:/path * * For compatibility with previous behaviour it also accepts as an NFS scheme @@ -387,10 +374,10 @@ net_print(int verbose) uint32_t net_parse_rootpath(void) { - n_long addr = htonl(INADDR_NONE); + n_long addr = 0; size_t i; char ip[FNAME_SIZE]; - char *ptr, *val; + char *ptr, *portp, *val; netproto = NET_NONE; @@ -405,10 +392,12 @@ net_parse_rootpath(void) ptr = rootpath; /* Fallback for compatibility mode */ if (netproto == NET_NONE) { - netproto = NET_NFS; + netproto = NETPROTO_DEFAULT; (void)strsep(&ptr, ":"); if (ptr != NULL) { addr = inet_addr(rootpath); + DEBUG_PRINTF(1,("rootpath=%s addr=%#x\n", + rootpath, addr)); bcopy(ptr, rootpath, strlen(ptr) + 1); } } else { @@ -416,16 +405,21 @@ net_parse_rootpath(void) if (*ptr == '/') { /* we are in the form <scheme>://, we do expect an ip */ ptr++; - /* - * XXX when http will be there we will need to check for - * a port, but right now we do not need it yet - */ + portp = val = strchr(ptr, ':'); + if (val != NULL) { + val++; + rootport = strtol(val, NULL, 10); + } val = strchr(ptr, '/'); if (val != NULL) { + if (portp == NULL) + portp = val; snprintf(ip, sizeof(ip), "%.*s", - (int)((uintptr_t)val - (uintptr_t)ptr), + (int)(portp - ptr), ptr); addr = inet_addr(ip); + DEBUG_PRINTF(1,("ip=%s addr=%#x\n", + ip, addr)); bcopy(val, rootpath, strlen(val) + 1); } } else { @@ -433,6 +427,7 @@ net_parse_rootpath(void) bcopy(ptr, rootpath, strlen(ptr) + 1); } } - + if (addr == 0) + addr = htonl(INADDR_NONE); return (addr); } diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c index 395332af9990..3de0a8b631ee 100644 --- a/stand/common/gfx_fb.c +++ b/stand/common/gfx_fb.c @@ -232,6 +232,68 @@ gfx_parse_mode_str(char *str, int *x, int *y, int *depth) return (true); } +/* + * Returns true if we set the color from pre-existing environment, false if + * just used existing defaults. + */ +static bool +gfx_fb_evalcolor(const char *envname, teken_color_t *cattr, + ev_sethook_t sethook, ev_unsethook_t unsethook) +{ + const char *ptr; + char env[10]; + int eflags = EV_VOLATILE | EV_NOKENV; + bool from_env = false; + + ptr = getenv(envname); + if (ptr != NULL) { + *cattr = strtol(ptr, NULL, 10); + + /* + * If we can't unset the value, then it's probably hooked + * properly and we can just carry on. Otherwise, we want to + * reinitialize it so that we can hook it for the console that + * we're resetting defaults for. + */ + if (unsetenv(envname) != 0) + return (true); + from_env = true; + + /* + * If we're carrying over an existing value, we *do* want that + * to propagate to the kenv. + */ + eflags &= ~EV_NOKENV; + } + + snprintf(env, sizeof(env), "%d", *cattr); + env_setenv(envname, eflags, env, sethook, unsethook); + + return (from_env); +} + +void +gfx_fb_setcolors(teken_attr_t *attr, ev_sethook_t sethook, + ev_unsethook_t unsethook) +{ + bool need_setattr = false; + + /* + * On first run, we setup an environment hook to process any color + * changes. If the env is already set, we pick up fg and bg color + * values from the environment. + */ + if (gfx_fb_evalcolor("teken.fg_color", &attr->ta_fgcolor, + sethook, unsethook)) + need_setattr = true; + if (gfx_fb_evalcolor("teken.bg_color", &attr->ta_bgcolor, + sethook, unsethook)) + need_setattr = true; + + if (need_setattr) + teken_set_defattr(&gfx_state.tg_teken, attr); +} + static uint32_t rgb_color_map(uint8_t index, uint32_t rmax, int roffset, uint32_t gmax, int goffset, uint32_t bmax, int boffset) @@ -1001,6 +1063,8 @@ gfx_fb_fill(void *arg, const teken_rect_t *r, teken_char_t c, teken_pos_t p; struct text_pixel *row; + TSENTER(); + /* remove the cursor */ if (state->tg_cursor_visible) gfx_fb_cursor_draw(state, &state->tg_cursor, false); @@ -1026,6 +1090,8 @@ gfx_fb_fill(void *arg, const teken_rect_t *r, teken_char_t c, c = teken_get_cursor(&state->tg_teken); gfx_fb_cursor_draw(state, c, true); } + + TSEXIT(); } static void @@ -2050,7 +2116,8 @@ gfx_get_ppi(void) * not smaller than calculated size value. */ static vt_font_bitmap_data_t * -gfx_get_font(void) +gfx_get_font(teken_unit_t rows, teken_unit_t cols, teken_unit_t height, + teken_unit_t width) { unsigned ppi, size; vt_font_bitmap_data_t *font = NULL; @@ -2073,6 +2140,14 @@ gfx_get_font(void) size = roundup(size * 2, 10) / 10; STAILQ_FOREACH(fl, &fonts, font_next) { + /* + * Skip too large fonts. + */ + font = fl->font_data; + if (height / font->vfbd_height < rows || + width / font->vfbd_width < cols) + continue; + next = STAILQ_NEXT(fl, font_next); /* @@ -2080,7 +2155,6 @@ gfx_get_font(void) * we have our font. Make sure, it actually is loaded. */ if (next == NULL || next->font_data->vfbd_height < size) { - font = fl->font_data; if (font->vfbd_font == NULL || fl->font_flags == FONT_RELOAD) { if (fl->font_load != NULL && @@ -2089,6 +2163,7 @@ gfx_get_font(void) } break; } + font = NULL; } return (font); @@ -2119,7 +2194,7 @@ set_font(teken_unit_t *rows, teken_unit_t *cols, teken_unit_t h, teken_unit_t w) } if (font == NULL) - font = gfx_get_font(); + font = gfx_get_font(*rows, *cols, h, w); if (font != NULL) { *rows = height / font->vfbd_height; diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h index 17e419d8ffd3..d12bcd76b7fa 100644 --- a/stand/common/gfx_fb.h +++ b/stand/common/gfx_fb.h @@ -277,6 +277,7 @@ void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, int gfx_fb_putimage(png_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); bool gfx_parse_mode_str(char *, int *, int *, int *); +void gfx_fb_setcolors(teken_attr_t *, ev_sethook_t, ev_unsethook_t); void term_image_display(teken_gfx_t *, const teken_rect_t *); void reset_font_flags(void); diff --git a/stand/common/install.c b/stand/common/install.c index b827b1fe9da2..d07c4c6fc620 100644 --- a/stand/common/install.c +++ b/stand/common/install.c @@ -137,7 +137,9 @@ read_metatags(int fd) } *p++ = '\0'; - if (strcmp(tag, "KERNEL") == 0) + if (strncmp(tag, "ENV_", 4) == 0) + setenv(&tag[4], val, 1); + else if (strcmp(tag, "KERNEL") == 0) error = setpath(&inst_kernel, val); else if (strcmp(tag, "MODULES") == 0) error = setmultipath(&inst_modules, val); @@ -212,6 +214,7 @@ install(char *pkgname) if (i == 4 && !strncasecmp(pkgname, "tftp", i)) { devname = "net0"; devnamelen = 4; + netproto = NET_TFTP; proto = &tftp_fsops; } else if (i == 4 && !strncasecmp(pkgname, "file", i)) { currdev = getenv("currdev"); diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c index e19aefa121e7..b9f55a21e403 100644 --- a/stand/common/load_elf.c +++ b/stand/common/load_elf.c @@ -30,11 +30,8 @@ #include <sys/exec.h> #include <sys/linker.h> #include <sys/module.h> -#include <sys/stdint.h> -#include <string.h> #include <machine/elf.h> #include <stand.h> -#include <sys/link_elf.h> #include "bootstrap.h" #include "modinfo.h" @@ -406,6 +403,7 @@ __elfN(loadfile_raw)(char *filename, uint64_t dest, * in the elf header (an ARM kernel can be loaded at any 2MB * boundary), so we leave dest set to the value calculated by * archsw.arch_loadaddr() and passed in to this function. + * XXX This comment is obsolete, but it still seems to work */ #ifndef __arm__ if (ehdr->e_type == ET_EXEC) @@ -448,10 +446,7 @@ __elfN(loadfile_raw)(char *filename, uint64_t dest, goto oerr; } - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); - else - dest = roundup(dest, PAGE_SIZE); + dest = md_align(dest); /* * Ok, we think we should handle this. diff --git a/stand/common/load_elf_obj.c b/stand/common/load_elf_obj.c index 1e07828dd8ac..9e32daa53696 100644 --- a/stand/common/load_elf_obj.c +++ b/stand/common/load_elf_obj.c @@ -30,11 +30,8 @@ #include <sys/exec.h> #include <sys/linker.h> #include <sys/module.h> -#include <stdint.h> -#include <string.h> #include <machine/elf.h> #include <stand.h> -#include <sys/link_elf.h> #include "bootstrap.h" #include "modinfo.h" @@ -160,10 +157,7 @@ __elfN(obj_loadfile)(char *filename, uint64_t dest, goto oerr; } - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); - else - dest = roundup(dest, PAGE_SIZE); + dest = md_align(dest); /* * Ok, we think we should handle this. diff --git a/stand/common/md.c b/stand/common/md.c index d12429c3c45c..2c3eb5ded19b 100644 --- a/stand/common/md.c +++ b/stand/common/md.c @@ -28,7 +28,7 @@ #include <sys/param.h> #include <sys/endian.h> #include <sys/queue.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> #include "bootstrap.h" diff --git a/stand/common/metadata.c b/stand/common/metadata.c index 22df6f175791..3b2ba3e4d790 100644 --- a/stand/common/metadata.c +++ b/stand/common/metadata.c @@ -111,7 +111,7 @@ md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); - if (rootdevname == NULL) + if (rootdevname == NULL || *rootdevname == '\0') rootdevname = getenv("currdev"); /* Try reading the /etc/fstab file to select the root device */ getrootmount(rootdevname); @@ -123,14 +123,14 @@ md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) addr = xp->f_addr + xp->f_size; } /* Pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); /* Copy our environment */ envp = addr; addr = md_copyenv(addr); /* Pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); #if defined(LOADER_FDT_SUPPORT) /* Copy out FDT */ @@ -141,7 +141,7 @@ md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) { size = fdt_copy(addr); fdtp = addr; - addr = roundup(addr + size, PAGE_SIZE); + addr = md_align(addr + size); } #endif @@ -176,7 +176,7 @@ md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) *modulep = addr; size = md_copymodules(0, kern64); - kernend = roundup(addr + size, PAGE_SIZE); + kernend = md_align(addr + size); md = file_findmetadata(kfp, MODINFOMD_KERNEND); if (kern64) { diff --git a/stand/common/misc.c b/stand/common/misc.c index 402213100951..a7c46ad2e74c 100644 --- a/stand/common/misc.c +++ b/stand/common/misc.c @@ -220,3 +220,16 @@ set_currdev(const char *devname) env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset, env_nounset); } + +#ifndef LOADER_NET_SUPPORT +/* + * This api is normally provided by dev_net.c + * This stub keeps libsa happy when LOADER_NET_SUPPORT + * is not enabled. + */ +bool +is_tftp(void) +{ + return false; +} +#endif diff --git a/stand/common/modinfo.c b/stand/common/modinfo.c index d00548c91c57..1e39bd858cc2 100644 --- a/stand/common/modinfo.c +++ b/stand/common/modinfo.c @@ -172,6 +172,8 @@ md_copyenv(vm_offset_t start) /* Traverse the environment. */ for (ep = environ; ep != NULL; ep = ep->ev_next) { + if ((ep->ev_flags & EV_NOKENV) != 0) + continue; len = strlen(ep->ev_name); if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len) break; @@ -194,3 +196,25 @@ md_copyenv(vm_offset_t start) last = start; return(last); } + +/* + * Take the ending address and round it up to the currently required + * alignment. This typically is the page size, but is the larger of the compiled + * kernel page size, the loader page size, and the typical page size on the + * platform. + * + * XXX For the moment, it's just PAGE_SIZE to make the refactoring go faster, + * but needs to hook-in the replacement of arch_loadaddr. + * + * Also, we may need other logical things when dealing with different types of + * page sizes and/or masking or sizes. This works well for addr and sizes, but + * not for masks. + * + * Also, this is different than the MOD_ALIGN macro above, which is used for + * aligning elements in the metadata lists, not for whare modules can begin. + */ +vm_offset_t +md_align(vm_offset_t addr) +{ + return (roundup(addr, PAGE_SIZE)); +} diff --git a/stand/common/modinfo.h b/stand/common/modinfo.h index d26129089fb6..d613d8e27f1f 100644 --- a/stand/common/modinfo.h +++ b/stand/common/modinfo.h @@ -16,5 +16,6 @@ int md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb); vm_offset_t md_copymodules(vm_offset_t addr, bool kern64); vm_offset_t md_copyenv(vm_offset_t addr); +vm_offset_t md_align(vm_offset_t addr); #endif /* COMMON_MODINFO_H */ diff --git a/stand/common/module.c b/stand/common/module.c index 0c9dbcb53c2e..bc06ba01fa06 100644 --- a/stand/common/module.c +++ b/stand/common/module.c @@ -43,6 +43,7 @@ #endif #include "bootstrap.h" +#include "modinfo.h" #define MDIR_REMOVED 0x0001 #define MDIR_NOHINTS 0x0002 @@ -65,7 +66,7 @@ static char * mod_searchmodule_pnpinfo(const char *bus, const char *pnpinfo); static void file_insert_tail(struct preloaded_file *mp); static void file_remove(struct preloaded_file *fp); static void file_remove_tail(struct preloaded_file *fp); -struct file_metadata* metadata_next(struct file_metadata *base_mp, int type); +static struct file_metadata * metadata_next(struct file_metadata *base_mp, int type); static void moduledir_readhints(struct moduledir *mdp); static void moduledir_rebuild(void); @@ -454,7 +455,8 @@ command_pnpload(int argc, char *argv[]) #if defined(LOADER_FDT_SUPPORT) static void -pnpautoload_fdt_bus(const char *busname) { +pnpautoload_fdt_bus(const char *busname) +{ const char *pnpstring; const char *compatstr; char *pnpinfo = NULL; @@ -552,7 +554,7 @@ command_pnpautoload(int argc, char *argv[]) /* * File level interface, functions file_* */ -int +static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) { static int last_file_format = 0; @@ -561,8 +563,7 @@ file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) int i; TSENTER2(filename); - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); + dest = md_align(dest); error = EFTYPE; for (i = last_file_format, fp = NULL; @@ -712,8 +713,7 @@ file_loadraw(const char *fname, const char *type, int insert) #endif #endif - if (archsw.arch_loadaddr != NULL) - loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); + loadaddr = md_align(loadaddr); if (module_verbose > MODULE_VERBOSE_SILENT) printf("%s ", name); @@ -915,7 +915,7 @@ file_findfile(const char *name, const char *type) * Find a module matching (name) inside of given file. * NULL may be passed as a wildcard. */ -struct kernel_module * +static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo) { @@ -1014,9 +1014,7 @@ file_addbuf(const char *name, const char *type, size_t len, void *buf) } /* Figure out where to load the data. */ - dest = loadaddr; - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_RAW, (void *)name, dest); + dest = md_align(loadaddr); /* Create & populate control structure */ fp = file_alloc(); @@ -1049,7 +1047,7 @@ file_addbuf(const char *name, const char *type, size_t len, void *buf) return(0); } -struct file_metadata * +static struct file_metadata * metadata_next(struct file_metadata *md, int type) { diff --git a/stand/common/newvers.sh b/stand/common/newvers.sh index c244e718c041..8541d61ed76c 100755 --- a/stand/common/newvers.sh +++ b/stand/common/newvers.sh @@ -50,13 +50,17 @@ if [ -n "$SOURCE_DATE_EPOCH" ]; then exit 1 fi else - t=`date` + t="${NEWVERS_DATE:-`date`}" fi r=`awk -F: ' /^[0-9]\.[0-9]+:/ { print $1; exit }' $1` bootprog_info="FreeBSD/${3} ${2}, Revision ${r}\\n" if [ -n "${include_metadata}" ]; then bootprog_info="$bootprog_info(${t} ${u}@${h})\\n" + if [ -n "$BUILD_UTC" ]; then + # We can use what(1) to extract BUILD_UTC + bootprog_info="$bootprog_info\\0@(#)BUILD_UTC=$BUILD_UTC" + fi fi cat > $tempfile <<EOF diff --git a/stand/defaults/loader.conf b/stand/defaults/loader.conf index b1e87520a2d4..036479d22285 100644 --- a/stand/defaults/loader.conf +++ b/stand/defaults/loader.conf @@ -95,6 +95,8 @@ audit_event_type="etc_security_audit_event" # Default is unset and disabled (no delay). #autoboot_delay="10" # Delay in seconds before autobooting, # -1 for no user interrupts, NO to disable +#print_delay="1000000" # Slow printing of loader messages, useful for + # debugging. Given in microseconds. #password="" # Prevent changes to boot options #bootlock_password="" # Prevent booting (see check-password.4th(8)) #geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root @@ -105,12 +107,14 @@ efi_max_resolution="1x1" # Set the max resolution for EFI loader to use: # WidthxHeight (e.g. 1920x1080) #kernels="kernel kernel.old" # Kernels to display in the boot menu kernels_autodetect="YES" # Auto-detect kernel directories in /boot +#loader_gfx="YES" # Use graphical images when available #loader_logo="orbbw" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none #comconsole_speed="115200" # Set the current serial console speed #console="vidconsole" # A comma separated list of console(s) #currdev="disk1s1a" # Set the current device module_path="/boot/modules;/boot/firmware;/boot/dtb;/boot/dtb/overlays" # Set the module search path -module_blacklist="drm drm2 radeonkms i915kms amdgpu" # Loader module blacklist +module_blacklist="drm drm2 radeonkms i915kms amdgpu if_iwlwifi if_rtw88 if_rtw89" # Loader module blacklist +module_blacklist="${module_blacklist} nvidia nvidia-drm nvidia-modeset" #prompt="\\${interpret}" # Set the command prompt #root_disk_unit="0" # Force the root disk unit number #rootdev="disk1s1a" # Set the root filesystem diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5 index 5ef54ee2c5d0..b1661e8c1101 100644 --- a/stand/defaults/loader.conf.5 +++ b/stand/defaults/loader.conf.5 @@ -21,7 +21,7 @@ .\" 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. -.Dd February 9, 2025 +.Dd September 2, 2025 .Dt LOADER.CONF 5 .Os .Sh NAME @@ -116,6 +116,10 @@ option in this manner, .Va beastie_disable must be set to .Dq Li YES . +.It Ar print_delay +Add a delay in microseconds after printing each line. +Default +.Dq Li 0 . .It Ar boot_* See list in .Xr loader.efi 8 @@ -123,6 +127,9 @@ since those flags apply to all boot loaders. .It Ar boot_verbose Set to "yes" to get the same effect as boot -v or booting verbose from the loader menu. +See the +.Va kern.msgbufsize +tuneable to ensure enough space for the increased number of messages. .It Ar exec Immediately executes a .Xr loader 8 @@ -410,6 +417,16 @@ be displayed. If set to .Dq YES , the beastie boot menu will be skipped. +.It Va loader_autoboot_show Pq Dq Li YES +If set to +.Dq NO , +the autoboot menu will not be displayed +.It Va loader_gfx +If set to +.Dq NO , +the ASCII art version of the brand and logo will be used even if graphical +versions are available. +Additionally, the menu frame will be drawn with ASCII art as well. .It Va loader_logo Pq Dq Li orbbw Selects a desired logo in the beastie boot menu. Possible values are: @@ -420,6 +437,10 @@ Possible values are: .Dq Li beastie , and .Dq Li none . +.It Va loader_menu +If set to +.Dq NONE , +the menu will not be displayed .It Va loader_color If set to .Dq NO , diff --git a/stand/defs.mk b/stand/defs.mk index f39966f2ca8e..eb4133b604eb 100644 --- a/stand/defs.mk +++ b/stand/defs.mk @@ -207,6 +207,8 @@ LOADER_INTERP?=${LOADER_DEFAULT_INTERP} # Make sure we use the machine link we're about to create CFLAGS+=-I. +.include "${BOOTSRC}/veriexec.mk" + all: ${PROG} CLEANFILES+= teken_state.h @@ -258,4 +260,6 @@ ${_ILINKS}: .NOMETA ${ECHO} ${.TARGET} "->" $$path ; \ ln -fns $$path ${.TARGET} .endif # !NO_OBJ + +.-include "local.defs.mk" .endif # __BOOT_DEFS_MK__ diff --git a/stand/efi/acpica/acpi_detect.c b/stand/efi/acpica/acpi_detect.c new file mode 100644 index 000000000000..1f15a882ff9d --- /dev/null +++ b/stand/efi/acpica/acpi_detect.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2014 Ed Maste <emaste@freebsd.org> + * Copyright (c) 2025 Kayla Powell <kpowkitty@FreeBSD.org> + * 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 <machine/_inttypes.h> +#include <efi.h> +#include <acpi.h> +#include "acpi_detect.h" + +/* For ACPI rsdp discovery. */ +EFI_GUID acpi = ACPI_TABLE_GUID; +EFI_GUID acpi20 = ACPI_20_TABLE_GUID; +ACPI_TABLE_RSDP *rsdp; + +void +acpi_detect(void) +{ + char buf[24]; + int revision; + + feature_enable(FEATURE_EARLY_ACPI); + if ((rsdp = efi_get_table(&acpi20)) == NULL) + if ((rsdp = efi_get_table(&acpi)) == NULL) + return; + + sprintf(buf, "0x%016"PRIxPTR, (uintptr_t)rsdp); + setenv("acpi.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("acpi.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("acpi.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("acpi.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("acpi.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("acpi.xsdt_length", buf, 1); + } +} diff --git a/stand/efi/acpica/include/acpi_detect.h b/stand/efi/acpica/include/acpi_detect.h new file mode 100644 index 000000000000..246e790be9fb --- /dev/null +++ b/stand/efi/acpica/include/acpi_detect.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Kayla Powell <kpowkitty@FreeBSD.org> + * 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. + */ + +#ifndef ACPI_DETECT_H +#define ACPI_DETECT_H + +#include <efi.h> +#include <efilib.h> + +struct ACPI_TABLE_RSDP; // forward declaration + +extern EFI_GUID acpi; +extern EFI_GUID acpi20; +extern ACPI_TABLE_RSDP *rsdp; + +void acpi_detect(void); + +#endif diff --git a/stand/efi/boot1/boot1.c b/stand/efi/boot1/boot1.c index 908baf400972..c906b430c0d6 100644 --- a/stand/efi/boot1/boot1.c +++ b/stand/efi/boot1/boot1.c @@ -20,8 +20,10 @@ */ #include <sys/param.h> +#include <sys/stdarg.h> + #include <machine/elf.h> -#include <machine/stdarg.h> + #include <stand.h> #include <efi.h> @@ -297,9 +299,9 @@ efi_exit(EFI_STATUS s) } void -exit(int error __unused) +exit(int error) { - efi_exit(EFI_LOAD_ERROR); + efi_exit(errno_to_efi_status(error)); } /* diff --git a/stand/efi/boot1/proto.c b/stand/efi/boot1/proto.c index 6660d39a921b..f81debd168b9 100644 --- a/stand/efi/boot1/proto.c +++ b/stand/efi/boot1/proto.c @@ -20,8 +20,10 @@ */ #include <sys/param.h> +#include <sys/stdarg.h> + #include <machine/elf.h> -#include <machine/stdarg.h> + #include <stand.h> #include <efi.h> diff --git a/stand/efi/gptboot/proto.c b/stand/efi/gptboot/proto.c index e2face6c23e5..a1825d9c1c15 100644 --- a/stand/efi/gptboot/proto.c +++ b/stand/efi/gptboot/proto.c @@ -24,8 +24,10 @@ */ #include <sys/param.h> +#include <sys/stdarg.h> + #include <machine/elf.h> -#include <machine/stdarg.h> + #include <stand.h> #include <efi.h> diff --git a/stand/efi/include/amd64/pe.h b/stand/efi/include/amd64/pe.h index b858ba916c7d..faf8eafde1e9 100644 --- a/stand/efi/include/amd64/pe.h +++ b/stand/efi/include/amd64/pe.h @@ -83,7 +83,7 @@ typedef struct _IMAGE_FILE_HEADER { #define IMAGE_SIZEOF_FILE_HEADER 20 #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. diff --git a/stand/efi/include/i386/pe.h b/stand/efi/include/i386/pe.h index c756080fe2d7..226c6c7564a7 100644 --- a/stand/efi/include/i386/pe.h +++ b/stand/efi/include/i386/pe.h @@ -83,7 +83,7 @@ typedef struct _IMAGE_FILE_HEADER { #define IMAGE_SIZEOF_FILE_HEADER 20 #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c index cbb4dd01d1fb..46a3c957f151 100644 --- a/stand/efi/libefi/efi_console.c +++ b/stand/efi/libefi/efi_console.c @@ -1041,28 +1041,7 @@ cons_update_mode(bool use_gfx_mode) a = teken_get_defattr(&gfx_state.tg_teken); attr = *a; - /* - * On first run, we set up the efi_set_colors() - * callback. If the env is already set, we - * pick up fg and bg color values from the environment. - */ - ptr = getenv("teken.fg_color"); - if (ptr != NULL) { - attr.ta_fgcolor = strtol(ptr, NULL, 10); - ptr = getenv("teken.bg_color"); - attr.ta_bgcolor = strtol(ptr, NULL, 10); - - teken_set_defattr(&gfx_state.tg_teken, &attr); - } else { - snprintf(env, sizeof(env), "%d", - attr.ta_fgcolor); - env_setenv("teken.fg_color", EV_VOLATILE, env, - efi_set_colors, env_nounset); - snprintf(env, sizeof(env), "%d", - attr.ta_bgcolor); - env_setenv("teken.bg_color", EV_VOLATILE, env, - efi_set_colors, env_nounset); - } + gfx_fb_setcolors(&attr, efi_set_colors, env_nounset); } } diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c index 186d816cd323..e872110ef08f 100644 --- a/stand/efi/libefi/efinet.c +++ b/stand/efi/libefi/efinet.c @@ -256,6 +256,7 @@ efi_env_net_params(struct iodesc *desc) rootip.s_addr = rootaddr; #ifdef EFINET_DEBUG + printf("%s: proto=%d\n", __func__, netproto); printf("%s: ip=%s\n", __func__, inet_ntoa(myip)); printf("%s: mask=%s\n", __func__, intoa(netmask)); printf("%s: gateway=%s\n", __func__, inet_ntoa(gateip)); @@ -427,6 +428,7 @@ efinet_dev_init(void) dif->dif_private = handles2[i]; } + efinet_dev.dv_cleanup = netdev.dv_cleanup; efinet_dev.dv_open = netdev.dv_open; efinet_dev.dv_close = netdev.dv_close; efinet_dev.dv_strategy = netdev.dv_strategy; diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index 2dae035f04a8..b4520b957b74 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -30,6 +30,10 @@ SRCS= autoload.c \ gfx_fb.c \ 8x16.c +SRCS+= acpi_detect.c +.PATH: ${EFISRC}/acpica +CFLAGS+= -I${EFISRC}/acpica/include + CFLAGS+= -I${.CURDIR}/../loader .if ${MK_LOADER_ZFS} != "no" CFLAGS+= -I${ZFSSRC} @@ -61,6 +65,7 @@ CWARNFLAGS.main.c+= -Wno-format .PATH: ${.CURDIR}/../loader/arch/${__arch} .include "${.CURDIR}/../loader/arch/${__arch}/Makefile.inc" +CFLAGS+= -Wall CFLAGS+= -I${.CURDIR} CFLAGS+= -I${.CURDIR}/arch/${__arch} CFLAGS+= -I${EFISRC}/include @@ -87,7 +92,7 @@ CFLAGS+= -DEFI_SECUREBOOT .endif NEWVERSWHAT?= "EFI loader" ${MACHINE} -VERSION_FILE= ${.CURDIR}/../loader/version +VERSION_FILE?= ${.CURDIR}/../loader/version HELP_FILENAME= loader.help.efi # Always add MI sources diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c index c4265aca035e..35bd4d6c1419 100644 --- a/stand/efi/loader/arch/amd64/elf64_freebsd.c +++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c @@ -209,6 +209,12 @@ elf64_exec(struct preloaded_file *fp) trampoline, PT4); printf("Start @ 0x%lx ...\n", ehdr->e_entry); + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + efi_time_fini(); err = bi_load(fp->f_args, &modulep, &kernend, true); if (err != 0) { @@ -218,8 +224,6 @@ elf64_exec(struct preloaded_file *fp) return (err); } - dev_cleanup(); - trampoline(trampstack, copy_staging == COPY_STAGING_ENABLE ? efi_copy_finish : efi_copy_finish_nop, kernend, modulep, PT4, ehdr->e_entry); diff --git a/stand/efi/loader/arch/amd64/multiboot2.c b/stand/efi/loader/arch/amd64/multiboot2.c index eb7362293406..6216fac42e4a 100644 --- a/stand/efi/loader/arch/amd64/multiboot2.c +++ b/stand/efi/loader/arch/amd64/multiboot2.c @@ -79,7 +79,6 @@ loadfile(char *filename, uint64_t dest, struct preloaded_file **result) void *multiboot = NULL; ssize_t search_size; struct multiboot_header *header; - char *cmdline; struct mb2hdr hdr; bool keep_bs = false; @@ -495,7 +494,6 @@ static int obj_loadfile(char *filename, uint64_t dest, struct preloaded_file **result) { struct preloaded_file *mfp, *kfp, *rfp; - struct kernel_module *kmp; int error; /* See if there's a multiboot kernel loaded */ diff --git a/stand/efi/loader/arch/amd64/trap.c b/stand/efi/loader/arch/amd64/trap.c index 95a42a18f719..37e7e9d263a7 100644 --- a/stand/efi/loader/arch/amd64/trap.c +++ b/stand/efi/loader/arch/amd64/trap.c @@ -87,7 +87,6 @@ report_exc(struct trapframe *tf) struct frame *fp; uintptr_t pc, base; char buf[80]; - int ret; base = (uintptr_t)boot_img->ImageBase; /* @@ -356,7 +355,7 @@ efi_redirect_exceptions(void) PREPARE_EXCEPTION(19); PREPARE_EXCEPTION(20); - exc_rsp = exc_stack_pa + PAGE_SIZE - + exc_rsp = exc_stack_pa + EFI_PAGE_SIZE - (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; /* Find free IST and use it */ @@ -376,7 +375,7 @@ efi_redirect_exceptions(void) if (intercepted[i]) loader_idt_e->gd_ist = ist; } - (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; + (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + EFI_PAGE_SIZE; /* Switch to new IDT */ rfl = intr_disable(); diff --git a/stand/efi/loader/arch/arm/exec.c b/stand/efi/loader/arch/arm/exec.c index c2a79523c02a..3963b6c0104b 100644 --- a/stand/efi/loader/arch/arm/exec.c +++ b/stand/efi/loader/arch/arm/exec.c @@ -74,16 +74,17 @@ __elfN(arm_exec)(struct preloaded_file *fp) printf("Kernel entry at %p...\n", entry); printf("Kernel args: %s\n", fp->f_args); + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) { efi_time_init(); return (error); } - /* At this point we've called ExitBootServices, so we can't call - * printf or any other function that uses Boot Services */ - - dev_cleanup(); - (*entry)((void *)modulep); panic("exec returned"); } diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c index 91a0503a976f..89e2ad7521a8 100644 --- a/stand/efi/loader/arch/arm64/exec.c +++ b/stand/efi/loader/arch/arm64/exec.c @@ -69,6 +69,12 @@ elf64_exec(struct preloaded_file *fp) ehdr = (Elf_Ehdr *)&(md->md_data); entry = efi_translate(ehdr->e_entry); + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + efi_time_fini(); err = bi_load(fp->f_args, &modulep, &kernendp, true); if (err != 0) { @@ -76,8 +82,6 @@ elf64_exec(struct preloaded_file *fp) return (err); } - dev_cleanup(); - /* Clean D-cache under kernel area and invalidate whole I-cache */ clean_addr = (vm_offset_t)efi_translate(fp->f_addr); clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr; diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c index b02cda2269bc..22cdd685ea9b 100644 --- a/stand/efi/loader/arch/i386/elf64_freebsd.c +++ b/stand/efi/loader/arch/i386/elf64_freebsd.c @@ -252,6 +252,13 @@ elf64_exec(struct preloaded_file *fp) ehdr->e_entry ); + + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + efi_time_fini(); err = bi_load(fp->f_args, &modulep, &kernend, true); if (err != 0) { @@ -259,8 +266,6 @@ elf64_exec(struct preloaded_file *fp) return (err); } - dev_cleanup(); - trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish : efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry); diff --git a/stand/efi/loader/arch/riscv/exec.c b/stand/efi/loader/arch/riscv/exec.c index 9da61229ef68..a53fbd9442b0 100644 --- a/stand/efi/loader/arch/riscv/exec.c +++ b/stand/efi/loader/arch/riscv/exec.c @@ -86,17 +86,17 @@ __elfN(exec)(struct preloaded_file *fp) printf("Kernel entry at %p...\n", entry); printf("Kernel args: %s\n", fp->f_args); + /* + * we have to cleanup here because net_cleanup() doesn't work after + * we call ExitBootServices + */ + dev_cleanup(); + if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) { efi_time_init(); return (error); } - /* - * At this point we've called ExitBootServices, so we can't call - * printf or any other function that uses Boot Services - */ - dev_cleanup(); - (*entry)((void *)modulep); panic("exec returned"); } diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index 75d755686658..7931622c2df6 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -67,9 +67,8 @@ static int bi_getboothowto(char *kargs) { -#ifdef EFI - const char *sw, *tmp; - char *opts; +#if defined(EFI) && (defined(__i386__) || defined(__amd64__)) + const char *tmp; int speed, port; char buf[50]; #endif @@ -389,18 +388,18 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) } /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); #ifdef EFI addr = build_font_module(addr); /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); addr = build_splash_module(addr); /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); #endif /* Copy our environment. */ @@ -408,7 +407,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) addr = md_copyenv(addr); /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); #if defined(LOADER_FDT_SUPPORT) /* Handle device tree blob */ @@ -417,7 +416,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) /* Pad to a page boundary */ if (dtb_size) - addr += roundup(dtb_size, PAGE_SIZE); + addr += md_align(dtb_size); #endif kfp = file_findfile(NULL, md_kerntype); @@ -461,7 +460,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) #endif size = md_copymodules(0, is64); /* Find the size of the modules */ - kernend = roundup(addr + size, PAGE_SIZE); + kernend = md_align(addr + size); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c index e4ad865a4acd..7452726565ad 100644 --- a/stand/efi/loader/copy.c +++ b/stand/efi/loader/copy.c @@ -248,7 +248,7 @@ static int command_staging_slop(int argc, char *argv[]) { char *endp; - u_long new, prev; + u_long new; if (argc > 2) { goto err; @@ -405,7 +405,9 @@ efi_check_space(vm_offset_t end) return (true); } +#if defined(__amd64__) || defined(__i386__) before_staging: +#endif /* Try allocating space before the previous allocation */ if (staging < nr_pages * EFI_PAGE_SIZE) goto expand; diff --git a/stand/efi/loader/efi_main.c b/stand/efi/loader/efi_main.c index 2a5120dc89d7..6eea6f25c152 100644 --- a/stand/efi/loader/efi_main.c +++ b/stand/efi/loader/efi_main.c @@ -49,7 +49,7 @@ void exit(int status) { - efi_exit(EFI_LOAD_ERROR); + efi_exit(errno_to_efi_status(status)); } static CHAR16 * diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c index 141a29305f7c..fc61ed15ba3c 100644 --- a/stand/efi/loader/framebuffer.c +++ b/stand/efi/loader/framebuffer.c @@ -630,7 +630,7 @@ efi_find_framebuffer(teken_gfx_t *gfx_state) gfx_state->tg_fb_type = FB_UGA; gfx_state->tg_private = uga; } else { - return (1); + return (efi_status_to_errno(status)); } } @@ -644,9 +644,12 @@ efi_find_framebuffer(teken_gfx_t *gfx_state) break; default: - return (1); + return (EINVAL); } + if (rv != 0) + return (rv); + gfx_state->tg_fb.fb_addr = efifb.fb_addr; gfx_state->tg_fb.fb_size = efifb.fb_size; gfx_state->tg_fb.fb_height = efifb.fb_height; diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 2384fd08b964..2e51f15f0b5f 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -69,12 +69,22 @@ #include "actypes.h" #include "actbl.h" +#include <acpi_detect.h> + #include "loader_efi.h" -struct arch_switch archsw; /* MI/MD interface boundary */ +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_autoload = efi_autoload, + .arch_getdev = efi_getdev, + .arch_copyin = efi_copyin, + .arch_copyout = efi_copyout, +#if defined(__amd64__) || defined(__i386__) + .arch_hypervisor = x86_hypervisor, +#endif + .arch_readin = efi_readin, + .arch_zfs_probe = efi_zfs_probe, +}; -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; @@ -110,11 +120,6 @@ UINT16 boot_current; */ EFI_LOADED_IMAGE *boot_img; -/* - * RSDP base table. - */ -ACPI_TABLE_RSDP *rsdp; - static bool has_keyboard(void) { @@ -305,9 +310,9 @@ probe_md_currdev(void) static bool try_as_currdev(pdinfo_t *hd, pdinfo_t *pp) { +#ifdef EFI_ZFS_BOOT uint64_t guid; -#ifdef EFI_ZFS_BOOT /* * If there's a zpool on this device, try it as a ZFS * filesystem, which has somewhat different setup than all @@ -495,8 +500,7 @@ match_boot_info(char *boot_info, size_t bisz) * a drop to the OK boot loader prompt is possible. */ static int -find_currdev(bool do_bootmgr, bool is_last, - char *boot_info, size_t boot_info_sz) +find_currdev(bool do_bootmgr, char *boot_info, size_t boot_info_sz) { pdinfo_t *dp, *pp; EFI_DEVICE_PATH *devpath, *copy; @@ -513,7 +517,7 @@ find_currdev(bool do_bootmgr, bool is_last, * it's wrong. */ rootdev = getenv("rootdev"); - if (rootdev != NULL) { + if (rootdev != NULL && *rootdev != '\0') { printf(" Setting currdev to configured rootdev %s\n", rootdev); set_currdev(rootdev); @@ -854,7 +858,7 @@ static int check_acpi_spcr(void) { ACPI_TABLE_SPCR *spcr; - int br, db, io, rs, rw, sb, xo, pv, pd; + int br, db, io, rs, rw, xo, pv, pd; uintmax_t mm; const char *dt, *pa; char *val = NULL; @@ -886,7 +890,6 @@ check_acpi_spcr(void) /* Uart settings */ pa = acpi_uart_parity(spcr->Parity); - sb = spcr->StopBits; db = 8; /* @@ -1111,6 +1114,8 @@ read_loader_env(const char *name, char *def_fn, bool once) printf(" Reading loader env vars from %s\n", fn); parse_loader_efi_config(boot_img->DeviceHandle, fn); } + + free(freeme); } caddr_t @@ -1120,39 +1125,6 @@ ptov(uintptr_t x) } static void -acpi_detect(void) -{ - char buf[24]; - int revision; - - feature_enable(FEATURE_EARLY_ACPI); - if ((rsdp = efi_get_table(&acpi20)) == NULL) - if ((rsdp = efi_get_table(&acpi)) == NULL) - return; - - sprintf(buf, "0x%016"PRIxPTR, (uintptr_t)rsdp); - setenv("acpi.rsdp", buf, 1); - revision = rsdp->Revision; - if (revision == 0) - revision = 1; - sprintf(buf, "%d", revision); - setenv("acpi.revision", buf, 1); - strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); - buf[sizeof(rsdp->OemId)] = '\0'; - setenv("acpi.oem", buf, 1); - sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); - setenv("acpi.rsdt", buf, 1); - if (revision >= 2) { - /* XXX extended checksum? */ - sprintf(buf, "0x%016llx", - (unsigned long long)rsdp->XsdtPhysicalAddress); - setenv("acpi.xsdt", buf, 1); - sprintf(buf, "%d", rsdp->Length); - setenv("acpi.xsdt_length", buf, 1); - } -} - -static void efi_smbios_detect(void) { VOID *smbios_v2_ptr = NULL; @@ -1191,27 +1163,17 @@ EFI_STATUS main(int argc, CHAR16 *argv[]) { int howto, i, uhowto; - bool has_kbd, is_last; + bool has_kbd; char *s; EFI_DEVICE_PATH *imgpath; CHAR16 *text; EFI_STATUS rv; - size_t sz, bosz = 0, bisz = 0; + size_t sz, bisz = 0; UINT16 boot_order[100]; char boot_info[4096]; char buf[32]; bool uefi_boot_mgr; - archsw.arch_autoload = efi_autoload; - archsw.arch_getdev = efi_getdev; - archsw.arch_copyin = efi_copyin; - archsw.arch_copyout = efi_copyout; -#if defined(__amd64__) || defined(__i386__) - archsw.arch_hypervisor = x86_hypervisor; -#endif - archsw.arch_readin = efi_readin; - archsw.arch_zfs_probe = efi_zfs_probe; - #if !defined(__arm__) efi_smbios_detect(); #endif @@ -1241,6 +1203,9 @@ main(int argc, CHAR16 *argv[]) #endif cons_probe(); + /* Set print_delay variable to have hooks in place. */ + env_setenv("print_delay", EV_VOLATILE, "", setprint_delay, env_nounset); + /* Set up currdev variable to have hooks in place. */ env_setenv("currdev", EV_VOLATILE, "", gen_setcurrdev, env_nounset); @@ -1401,17 +1366,13 @@ main(int argc, CHAR16 *argv[]) printf(" %04x%s", boot_order[i], boot_order[i] == boot_current ? "[*]" : ""); printf("\n"); - is_last = boot_order[(sz / sizeof(boot_order[0])) - 1] == boot_current; - bosz = sz; } else if (uefi_boot_mgr) { /* * u-boot doesn't set BootOrder, but otherwise participates in the * boot manager protocol. So we fake it here and don't consider it * a failure. */ - bosz = sizeof(boot_order[0]); boot_order[0] = boot_current; - is_last = true; } } @@ -1460,7 +1421,7 @@ main(int argc, CHAR16 *argv[]) * the boot protocol and also allow an escape hatch for users wishing * to try something different. */ - if (find_currdev(uefi_boot_mgr, is_last, boot_info, bisz) != 0) + if (find_currdev(uefi_boot_mgr, boot_info, bisz) != 0) if (uefi_boot_mgr && !interactive_interrupt("Failed to find bootable partition")) return (EFI_NOT_FOUND); @@ -1547,6 +1508,7 @@ command_seed_entropy(int argc, char *argv[]) } COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff); +COMMAND_SET(halt, "halt", "power off the system", command_poweroff); static int command_poweroff(int argc __unused, char *argv[] __unused) @@ -1854,6 +1816,8 @@ command_chain(int argc, char *argv[]) EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; EFI_HANDLE loaderhandle; EFI_LOADED_IMAGE *loaded_image; + UINTN ExitDataSize; + CHAR16 *ExitData = NULL; EFI_STATUS status; struct stat st; struct devdesc *dev; @@ -1969,9 +1933,16 @@ command_chain(int argc, char *argv[]) } dev_cleanup(); - status = BS->StartImage(loaderhandle, NULL, NULL); + + status = BS->StartImage(loaderhandle, &ExitDataSize, &ExitData); if (status != EFI_SUCCESS) { - command_errmsg = "StartImage failed"; + printf("StartImage failed (%lu)", EFI_ERROR_CODE(status)); + if (ExitData != NULL) { + printf(": %S", ExitData); + BS->FreePool(ExitData); + } + putchar('\n'); + command_errmsg = ""; free(loaded_image->LoadOptions); loaded_image->LoadOptions = NULL; status = BS->UnloadImage(loaded_image); diff --git a/stand/fdt/fdt_loader_cmd.c b/stand/fdt/fdt_loader_cmd.c index c51e8c5ab583..161c2435c410 100644 --- a/stand/fdt/fdt_loader_cmd.c +++ b/stand/fdt/fdt_loader_cmd.c @@ -990,7 +990,7 @@ int fdt_copy(vm_offset_t va) { int err; - debugf("fdt_copy va 0x%08x\n", va); + debugf("fdt_copy va 0x%08jx\n", (uintmax_t)va); if (fdtp == NULL) { err = fdt_setup_fdtp(); if (err) { @@ -1240,13 +1240,6 @@ fdt_cmd_ls(int argc, char *argv[]) return (CMD_OK); } -static __inline int -isprint(int c) -{ - - return (c >= ' ' && c <= 0x7e); -} - static int fdt_isprint(const void *data, int len, int *count) { diff --git a/stand/ficl/loader.c b/stand/ficl/loader.c index 69a65ebedb73..32ec2d6fc172 100644 --- a/stand/ficl/loader.c +++ b/stand/ficl/loader.c @@ -864,6 +864,9 @@ void ficlCompilePlatform(FICL_SYSTEM *pSys) dictAppendWord(dp, "ccall", ficlCcall, FW_DEFAULT); dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT); dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT); +#ifndef TESTMAIN + dictAppendWord(dp, "isvirtualized?", ficlIsvirtualizedQ, FW_DEFAULT); +#endif SET_FOREACH(fnpp, X4th_compile_set) (*fnpp)(pSys); diff --git a/stand/fonts/Makefile b/stand/fonts/Makefile index 3ac1b0bac951..4840c07201d6 100644 --- a/stand/fonts/Makefile +++ b/stand/fonts/Makefile @@ -1,5 +1,6 @@ .include <bsd.init.mk> +.PATH: ${SRCTOP}/contrib/spleen .PATH: ${SRCTOP}/contrib/terminus FONTS= \ @@ -15,6 +16,7 @@ FONTS= \ 12x24.fnt.gz \ 14x28.fnt.gz \ 16x32.fnt.gz \ + 32x64.fnt.gz \ FILES= ${FONTS} INDEX.fonts FILESDIR= /boot/fonts @@ -45,6 +47,8 @@ CLEANFILES+= ${FONTS} ${FONTS:T:S/${COMPRESS_EXT}//g} ${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET} 16x32.fnt.gz: 16x32.fnt ${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET} +32x64.fnt.gz: 32x64.fnt + ${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET} 6x12.fnt: ter-u12n.bdf ter-u12b.bdf vtfontcvt -o ${.TARGET} ${.ALLSRC} @@ -82,4 +86,7 @@ CLEANFILES+= ${FONTS} ${FONTS:T:S/${COMPRESS_EXT}//g} 16x32.fnt: ter-u32n.bdf ter-u32b.bdf vtfontcvt -o ${.TARGET} ${.ALLSRC} +32x64.fnt: spleen-32x64.bdf + vtfontcvt -o ${.TARGET} ${.ALLSRC} + .include <bsd.prog.mk> diff --git a/stand/i386/Makefile b/stand/i386/Makefile index 768496598575..299e070d8cd5 100644 --- a/stand/i386/Makefile +++ b/stand/i386/Makefile @@ -18,7 +18,7 @@ SUBDIR.yes+= loader_simp # special boot programs, 'self-extracting boot2+loader' SUBDIR.${MK_LOADER_PXEBOOT}+= pxeldr -SUBDIR.${MK_LOADER_ZFS}+= zfsboot gptzfsboot +SUBDIR.${MK_LOADER_ZFS}+= gptzfsboot .if defined(PXEBOOT_DEFAULT_INTERP) L=${PXEBOOT_DEFAULT_INTERP} diff --git a/stand/i386/boot2/Makefile b/stand/i386/boot2/Makefile index 313bb8030f3e..94dbd7af29d6 100644 --- a/stand/i386/boot2/Makefile +++ b/stand/i386/boot2/Makefile @@ -33,7 +33,8 @@ CFLAGS+=-fomit-frame-pointer \ CFLAGS.gcc+= -Os \ -fno-asynchronous-unwind-tables \ - --param max-inline-insns-single=100 + --param max-inline-insns-single=100 \ + --param min-pagesize=1024 CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL} diff --git a/stand/i386/cdboot/Makefile b/stand/i386/cdboot/Makefile index c66ff68105c1..15b73856c086 100644 --- a/stand/i386/cdboot/Makefile +++ b/stand/i386/cdboot/Makefile @@ -3,6 +3,7 @@ PROG= cdboot STRIP= BINMODE=${NOBINMODE} +MAN= cdboot.8 SRCS= ${PROG}.S CFLAGS+=-I${BOOTSRC}/i386/common diff --git a/stand/i386/cdboot/cdboot.8 b/stand/i386/cdboot/cdboot.8 new file mode 100644 index 000000000000..6163bd7b4a7a --- /dev/null +++ b/stand/i386/cdboot/cdboot.8 @@ -0,0 +1,21 @@ +.\" +.\" Copyright (c) 2025 Alexander Ziaee +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd May 9 2025 +.Dt CDBOOT 8 i386 +.Os +.Sh NAME +.Nm cdboot +.Nd find a bootloader on ISO-9660 +.Sh DESCRIPTION +.Nm +is a small boot block which finds +.Xr loader 8 +on a +.Xr cd9660 4 +file system. +.Sh SEE ALSO +.Xr cd9660 4 , +.Xr loader 8 diff --git a/stand/i386/common/bootargs.h b/stand/i386/common/bootargs.h index dafcf6a55554..072f7ee505fd 100644 --- a/stand/i386/common/bootargs.h +++ b/stand/i386/common/bootargs.h @@ -88,7 +88,7 @@ struct bootargs /* * geli_boot_data is embedded in geli_boot_args (passed from gptboot to loader) - * and in zfs_boot_args (passed from zfsboot and gptzfsboot to loader). + * and in zfs_boot_args (passed from gptzfsboot to loader). */ struct geli_boot_data { diff --git a/stand/i386/gptboot/Makefile b/stand/i386/gptboot/Makefile index b91875d242f5..366d82497819 100644 --- a/stand/i386/gptboot/Makefile +++ b/stand/i386/gptboot/Makefile @@ -1,6 +1,6 @@ .include <bsd.init.mk> -.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC} +.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common FILES= gptboot MAN= gptboot.8 @@ -34,7 +34,8 @@ CFLAGS+=-DBOOTPROG=\"gptboot\" \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Wno-pointer-sign -CFLAGS.gcc+= --param max-inline-insns-single=100 +CFLAGS.gcc+= --param max-inline-insns-single=100 \ + --param min-pagesize=1024 LD_FLAGS+=${LD_FLAGS_BIN} @@ -53,12 +54,12 @@ gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o drv.o \ - cons.o ${OPENCRYPTO_XTS} + cons.o gptboot.bin: gptboot.out ${OBJCOPY} -S -O binary gptboot.out ${.TARGET} -gptboot.out: ${BTXCRT} gptboot.o sio.o drv.o cons.o ${OPENCRYPTO_XTS} +gptboot.out: ${BTXCRT} gptboot.o sio.o drv.o cons.o ${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} .include <bsd.prog.mk> diff --git a/stand/i386/gptzfsboot/Makefile b/stand/i386/gptzfsboot/Makefile index 0d9fa8b043df..ebdd4958c5f2 100644 --- a/stand/i386/gptzfsboot/Makefile +++ b/stand/i386/gptzfsboot/Makefile @@ -1,7 +1,7 @@ .include <bsd.init.mk> .PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \ - ${BOOTSRC}/i386/zfsboot ${BOOTSRC}/i386/common \ + ${BOOTSRC}/i386/common \ ${BOOTSRC}/common FILES= gptzfsboot @@ -46,7 +46,8 @@ CFLAGS.clang+= -Wno-tentative-definition-incomplete-type NO_WCAST_ALIGN= -CFLAGS.gcc+= --param max-inline-insns-single=100 +CFLAGS.gcc+= --param max-inline-insns-single=100 \ + --param min-pagesize=1024 LD_FLAGS+=${LD_FLAGS_BIN} @@ -65,7 +66,7 @@ gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o OBJS= zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o misc.o -CLEANFILES+= gptzfsboot.bin gptzfsboot.out ${OBJS} ${OPENCRYPTO_XTS} +CLEANFILES+= gptzfsboot.bin gptzfsboot.out ${OBJS} # i386 standalone support library LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a @@ -73,8 +74,7 @@ LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a gptzfsboot.bin: gptzfsboot.out ${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET} -gptzfsboot.out: ${BTXCRT} ${OBJS} \ - ${OPENCRYPTO_XTS} +gptzfsboot.out: ${BTXCRT} ${OBJS} ${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32} zfsboot.o: ${ZFSSRC}/zfsimpl.c diff --git a/stand/i386/zfsboot/zfsboot.c b/stand/i386/gptzfsboot/zfsboot.c index 07bf31eac7a1..4c8eae9b65e5 100644 --- a/stand/i386/zfsboot/zfsboot.c +++ b/stand/i386/gptzfsboot/zfsboot.c @@ -131,7 +131,16 @@ static int parse_cmd(void); static char gelipw[GELI_PW_MAXLEN]; #endif -struct arch_switch archsw; /* MI/MD interface boundary */ +/* + * Only because the zfs code requires access through archsw, otherwise the + * 'boot' programs don't need archsw. This is less than ideal, but this + * workaround is easier than many of the alternatives. + */ +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_getdev = i386_getdev, + .arch_zfs_probe = i386_zfs_probe, +}; + static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ struct devsw *devsw[] = { @@ -184,15 +193,6 @@ main(void) */ bcache_init(32768, 512); - archsw.arch_autoload = NULL; - archsw.arch_getdev = i386_getdev; - archsw.arch_copyin = NULL; - archsw.arch_copyout = NULL; - archsw.arch_readin = NULL; - archsw.arch_isainb = NULL; - archsw.arch_isaoutb = NULL; - archsw.arch_zfs_probe = i386_zfs_probe; - bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_size = sizeof(bootinfo); bootinfo.bi_basemem = bios_basemem / 1024; diff --git a/stand/i386/isoboot/Makefile b/stand/i386/isoboot/Makefile index 7973f8029aa0..bf22e0f21d59 100644 --- a/stand/i386/isoboot/Makefile +++ b/stand/i386/isoboot/Makefile @@ -1,7 +1,7 @@ .include <bsd.init.mk> .PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \ - ${BOOTSRC}/i386/common ${SASRC} + ${BOOTSRC}/i386/common FILES= isoboot MAN= isoboot.8 @@ -29,7 +29,8 @@ CFLAGS+=-DBOOTPROG=\"isoboot\" \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Wno-pointer-sign -CFLAGS.gcc+= --param max-inline-insns-single=100 +CFLAGS.gcc+= --param max-inline-insns-single=100 \ + --param min-pagesize=1024 CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL} LD_FLAGS+=${LD_FLAGS_BIN} @@ -51,12 +52,12 @@ gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o CLEANFILES+= isoboot.bin isoboot.out isoboot.o sio.o drv.o \ - cons.o ${OPENCRYPTO_XTS} + cons.o isoboot.bin: isoboot.out ${OBJCOPY} -S -O binary isoboot.out ${.TARGET} -isoboot.out: ${BTXCRT} isoboot.o sio.o drv.o cons.o ${OPENCRYPTO_XTS} +isoboot.out: ${BTXCRT} isoboot.o sio.o drv.o cons.o ${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} .include <bsd.prog.mk> diff --git a/stand/i386/libi386/Makefile b/stand/i386/libi386/Makefile index 038557c6a826..7205d3a61988 100644 --- a/stand/i386/libi386/Makefile +++ b/stand/i386/libi386/Makefile @@ -7,6 +7,7 @@ SRCS+= bio.c SRCS+= biosacpi.c SRCS+= biosdisk.c SRCS+= biosmem.c +SRCS+= biosmemdisk.c SRCS+= biospci.c SRCS+= biospnp.c SRCS+= biossmap.c diff --git a/stand/i386/libi386/biosacpi.c b/stand/i386/libi386/biosacpi.c index 077b6c7e53de..8ddd322b9f99 100644 --- a/stand/i386/libi386/biosacpi.c +++ b/stand/i386/libi386/biosacpi.c @@ -25,7 +25,7 @@ */ #include <stand.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> #include <bootstrap.h> #include <btxv86.h> #include "libi386.h" diff --git a/stand/i386/libi386/biosmemdisk.c b/stand/i386/libi386/biosmemdisk.c new file mode 100644 index 000000000000..208ae289950a --- /dev/null +++ b/stand/i386/libi386/biosmemdisk.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2020 Richard Russo <russor@ruka.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Source of information: https://repo.or.cz/syslinux.git + * + * Implements the MEMDISK protocol from syslinux, found in doc/memdisk.txt + * (search MEMDISK info structure). Since we validate the pointer to the mBFT, a + * minimum version of 3.85 is needed. Note: All this could be done in the + * kernel, since we don't have hooks to use this inside the boot loader. The + * details of these structures can be found in memdisk/memdisk.inc (search + * for mBFT). + * + * The kernel could just grab the mBFT table, but instead relies on us finding + * it and setting the right env variables. + */ +#include <stand.h> +#include <machine/stdarg.h> +#include <bootstrap.h> +#include <btxv86.h> +#include "libi386.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +struct memdisk_info { + uint32_t mdi_13h_hook_ptr; /* not included in mdi_length! */ + uint16_t mdi_length; + uint8_t mdi_minor; + uint8_t mdi_major; + uint32_t mdi_disk_ptr; + uint32_t mdi_disk_sectors; + uint32_t mdi_far_ptr_cmdline; + uint32_t mdi_old_int13h; + uint32_t mdi_old_int15h; + uint16_t mdi_dos_mem_before; + uint8_t mdi_boot_loader_id; + uint8_t mdi_sector_size; /* Code below assumes this is last */ +} __attribute__((packed)); + +struct safe_13h_hook { + char sh_jmp[3]; + char sh_id[8]; + char sh_vendor[8]; + uint16_t sh_next_offset; + uint16_t sh_next_segment; + uint32_t sh_flags; + uint32_t sh_mbft; +} __attribute__((packed)); + +/* + * Maximum length of INT 13 entries we'll chase. Real disks are on this list, + * potentially, so we may have to look through them to find the memdisk. + */ +#define MEMDISK_MAX 32 + +/* + * Scan for MEMDISK virtual block devices + */ +void +biosmemdisk_detect(void) +{ + char line[80], scratch[80]; + int hook = 0, count = 0, sector_size; + uint16_t segment, offset; + struct safe_13h_hook *probe; + ACPI_TABLE_HEADER *mbft; + uint8_t *cp, sum; + struct memdisk_info *mdi; + + /* + * Walk through the int13 handler linked list, looking for possible + * MEMDISKs. + * + * The max is arbitrary to ensure termination. + */ + offset = *(uint16_t *)PTOV(0x13 * 4); + segment = *(uint16_t *)PTOV(0x13 * 4 + 2); + while (hook < MEMDISK_MAX && !(segment == 0 && offset == 0)) { + /* + * Walk the linked list, making sure each node has the right + * signature and only looking at MEMDISK nodes. + */ + probe = (struct safe_13h_hook *)PTOV(segment * 16 + offset); + if (memcmp(probe->sh_id, "$INT13SF", sizeof(probe->sh_id)) != 0) { + printf("Found int 13h unsafe hook at %p (%x:%x)\n", + probe, segment, offset); + break; + } + if (memcmp(probe->sh_vendor, "MEMDISK ", sizeof(probe->sh_vendor)) != 0) + goto end_of_loop; + + /* + * If it is a memdisk, make sure the mBFT signature is correct + * and its checksum is right. + */ + mbft = (ACPI_TABLE_HEADER *)PTOV(probe->sh_mbft); + if (memcmp(mbft->Signature, "mBFT", sizeof(mbft->Signature)) != 0) + goto end_of_loop; + sum = 0; + cp = (uint8_t *)mbft; + for (int idx = 0; idx < mbft->Length; ++idx) + sum += *(cp + idx); + if (sum != 0) + goto end_of_loop; + + /* + * The memdisk info follows the ACPI_TABLE_HEADER in the mBFT + * section. If the sector size is present and non-zero use it + * otherwise assume 512. + */ + mdi = (struct memdisk_info *)PTOV(probe->sh_mbft + sizeof(*mbft)); + sector_size = 512; + if (mdi->mdi_length + sizeof(mdi->mdi_13h_hook_ptr) >= sizeof(*mdi) && + mdi->mdi_sector_size != 0) + sector_size = 1 << mdi->mdi_sector_size; + + printf("memdisk %d.%d disk at %#x (%d sectors = %d bytes)\n", + mdi->mdi_major, mdi->mdi_minor, mdi->mdi_disk_ptr, + mdi->mdi_disk_sectors, mdi->mdi_disk_sectors * sector_size); + + snprintf(line, sizeof(line), "hint.md.%d.physaddr", count); + snprintf(scratch, sizeof(scratch), "0x%08x", mdi->mdi_disk_ptr); + setenv(line, scratch, 1); + snprintf(line, sizeof(line), "hint.md.%d.len", count); + snprintf(scratch, sizeof(scratch), "%d", mdi->mdi_disk_sectors * sector_size); + setenv(line, scratch, 1); + count++; +end_of_loop: + hook++; + offset = probe->sh_next_offset; + segment = probe->sh_next_segment; + } +} diff --git a/stand/i386/libi386/biospci.c b/stand/i386/libi386/biospci.c index 5b39eab1e5e5..a89a6d30a1e8 100644 --- a/stand/i386/libi386/biospci.c +++ b/stand/i386/libi386/biospci.c @@ -31,7 +31,7 @@ */ #include <stand.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> #include <bootstrap.h> #include <isapnp.h> #include <btxv86.h> diff --git a/stand/i386/libi386/biospnp.c b/stand/i386/libi386/biospnp.c index 5b22f066d4ef..c01d2888a9f7 100644 --- a/stand/i386/libi386/biospnp.c +++ b/stand/i386/libi386/biospnp.c @@ -29,7 +29,7 @@ */ #include <stand.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> #include <bootstrap.h> #include <isapnp.h> #include <btxv86.h> diff --git a/stand/i386/libi386/bootinfo32.c b/stand/i386/libi386/bootinfo32.c index 37b227b913bd..6655e62f8065 100644 --- a/stand/i386/libi386/bootinfo32.c +++ b/stand/i386/libi386/bootinfo32.c @@ -118,7 +118,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); addr = build_font_module(addr); @@ -127,7 +127,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t addr = md_copyenv(addr); /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); kfp = file_findfile(NULL, md_kerntype); if (kfp == NULL) @@ -145,7 +145,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t /* Figure out the size and location of the metadata */ *modulep = addr; size = md_copymodules(0, false); - kernend = roundup(addr + size, PAGE_SIZE); + kernend = md_align(addr + size); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ diff --git a/stand/i386/libi386/bootinfo64.c b/stand/i386/libi386/bootinfo64.c index f7181dcd599f..7d74a865ff40 100644 --- a/stand/i386/libi386/bootinfo64.c +++ b/stand/i386/libi386/bootinfo64.c @@ -136,7 +136,7 @@ bi_load64(char *args, vm_offset_t *modulep, addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); addr = build_font_module(addr); @@ -161,11 +161,11 @@ bi_load64(char *args, vm_offset_t *modulep, size = md_copymodules(0, true); /* copy our environment */ - envp = roundup(addr + size, PAGE_SIZE); + envp = md_align(addr + size); addr = md_copyenv(envp); /* set kernend */ - kernend = roundup(addr, PAGE_SIZE); + kernend = md_align(addr); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ diff --git a/stand/i386/libi386/libi386.h b/stand/i386/libi386/libi386.h index d456ef58d7c2..caf565dd0656 100644 --- a/stand/i386/libi386/libi386.h +++ b/stand/i386/libi386/libi386.h @@ -149,3 +149,5 @@ int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend, int add_smap); void pxe_enable(void *pxeinfo); + +void biosmemdisk_detect(void); diff --git a/stand/i386/libi386/vidconsole.c b/stand/i386/libi386/vidconsole.c index 414803e9af3d..3938bd7822ea 100644 --- a/stand/i386/libi386/vidconsole.c +++ b/stand/i386/libi386/vidconsole.c @@ -956,26 +956,7 @@ cons_update_mode(bool use_gfx_mode) a = teken_get_defattr(&gfx_state.tg_teken); attr = *a; - /* - * On first run, we set up the vidc_set_colors() - * callback. If the env is already set, we - * pick up fg and bg color values from the environment. - */ - ptr = getenv("teken.fg_color"); - if (ptr != NULL) { - attr.ta_fgcolor = strtol(ptr, NULL, 10); - ptr = getenv("teken.bg_color"); - attr.ta_bgcolor = strtol(ptr, NULL, 10); - - teken_set_defattr(&gfx_state.tg_teken, &attr); - } else { - snprintf(env, sizeof(env), "%d", attr.ta_fgcolor); - env_setenv("teken.fg_color", EV_VOLATILE, env, - vidc_set_colors, env_nounset); - snprintf(env, sizeof(env), "%d", attr.ta_bgcolor); - env_setenv("teken.bg_color", EV_VOLATILE, env, - vidc_set_colors, env_nounset); - } + gfx_fb_setcolors(&attr, vidc_set_colors, env_nounset); /* Improve visibility */ if (attr.ta_bgcolor == TC_WHITE) diff --git a/stand/i386/loader/Makefile b/stand/i386/loader/Makefile index bb9111c3dcce..96ad50a75509 100644 --- a/stand/i386/loader/Makefile +++ b/stand/i386/loader/Makefile @@ -16,7 +16,7 @@ LOADER?= loader_${LOADER_INTERP} PROG= ${LOADER}.sym INTERNALPROG= NEWVERSWHAT?= "bootstrap loader" x86 -VERSION_FILE= ${.CURDIR}/../loader/version +VERSION_FILE?= ${.CURDIR}/../loader/version # # There's 640k - 40k maximum space, less however much memory the BIOS uses. A # non-random survey suggests that 20k-25k is a good value for 'most' machines. @@ -90,7 +90,8 @@ ORG= 0x0 CFLAGS+= -Wall LDFLAGS+= -static ${LDFLAGS_ORG} -Wl,--gc-sections -.if ${LINKER_TYPE} == "lld" && ${LINKER_VERSION} >= 130000 +.if (${LINKER_TYPE} == "lld" && ${LINKER_VERSION} >= 130000) || \ + (${LINKER_TYPE} == "bfd" && ${LINKER_VERSION} >= 23700) # lld 13 and higher default to garbage collecting start/stop symbols, # completely ruining our linker sets. For now, work around it by # disabling this un-feature. diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c index e7a42c194326..a70b3a253b90 100644 --- a/stand/i386/loader/main.c +++ b/stand/i386/loader/main.c @@ -61,21 +61,35 @@ static uint32_t initial_howto; static uint32_t initial_bootdev; static struct bootinfo *initial_bootinfo; -struct arch_switch archsw; /* MI/MD interface boundary */ - -static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); + +#ifdef LOADER_ZFS_SUPPORT +struct zfs_boot_args *zargs; +static void i386_zfs_probe(void); +#endif + +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_autoload = i386_autoload, + .arch_getdev = i386_getdev, + .arch_copyin = i386_copyin, + .arch_copyout = i386_copyout, + .arch_readin = i386_readin, + .arch_isainb = isa_inb, + .arch_isaoutb = isa_outb, + .arch_hypervisor = x86_hypervisor, +#ifdef LOADER_ZFS_SUPPORT + .arch_zfs_probe = i386_zfs_probe, +#endif +}; + +static void extract_currdev(void); void exit(int code); #ifdef LOADER_GELI_SUPPORT #include "geliboot.h" struct geli_boot_args *gargs; struct geli_boot_data *gbdata; #endif -#ifdef LOADER_ZFS_SUPPORT -struct zfs_boot_args *zargs; -static void i386_zfs_probe(void); -#endif /* XXX debugging */ extern char end[]; @@ -182,19 +196,9 @@ main(void) bc_add(initial_bootdev); } - archsw.arch_autoload = i386_autoload; - archsw.arch_getdev = i386_getdev; - archsw.arch_copyin = i386_copyin; - archsw.arch_copyout = i386_copyout; - archsw.arch_readin = i386_readin; - archsw.arch_isainb = isa_inb; - archsw.arch_isaoutb = isa_outb; - archsw.arch_hypervisor = x86_hypervisor; #ifdef LOADER_ZFS_SUPPORT - archsw.arch_zfs_probe = i386_zfs_probe; - /* - * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS, + * gptzfsboot has always passed KARGS_FLAGS_ZFS, * so if that is set along with KARGS_FLAGS_EXTARG we know we * can interpret the extarg data as a struct zfs_boot_args. */ @@ -247,6 +251,9 @@ main(void) initial_bootinfo->bi_extmem = bios_extmem / 1024; } + /* detect MEMDISK virtual disks */ + biosmemdisk_detect(); + /* detect SMBIOS for future reference */ smbios_detect(NULL); diff --git a/stand/i386/zfsboot/Makefile b/stand/i386/zfsboot/Makefile deleted file mode 100644 index b619b84c368e..000000000000 --- a/stand/i386/zfsboot/Makefile +++ /dev/null @@ -1,92 +0,0 @@ -.include <bsd.init.mk> - -.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${BOOTSRC}/common - -FILES= zfsboot -MAN= zfsboot.8 - -BOOT_COMCONSOLE_PORT?= 0x3f8 -BOOT_COMCONSOLE_SPEED?= 115200 -B2SIOFMT?= 0x3 - -REL1= 0x700 -ORG1= 0x7c00 -ORG2= 0x2000 - -CFLAGS+=-DBOOTPROG=\"zfsboot\" \ - -O1 \ - -DBOOT2 \ - -DLOADER_GPT_SUPPORT \ - -DLOADER_MBR_SUPPORT \ - -DLOADER_ZFS_SUPPORT \ - -DLOADER_UFS_SUPPORT \ - -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ - -DSIOFMT=${B2SIOFMT} \ - -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ - -I${LDRSRC} \ - -I${BOOTSRC}/i386/common \ - -I${BOOTSRC}/i386/libi386 \ - -I${ZFSSRC} \ - -I${SYSDIR}/crypto/skein \ - -I${SYSDIR}/cddl/boot/zfs \ - -I${SYSDIR}/contrib/openzfs/include \ - -I${SYSDIR}/contrib/openzfs/include/os/freebsd/spl \ - -I${SYSDIR}/contrib/openzfs/include/os/freebsd/zfs \ - -I${SYSDIR}/cddl/contrib/opensolaris/common/lz4 \ - -I${BOOTSRC}/i386/boot2 \ - -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ - -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ - -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings - -CFLAGS.part.c+= -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib - -CFLAGS.gcc+= --param max-inline-insns-single=100 - -LD_FLAGS+=${LD_FLAGS_BIN} - -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 --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} zfsldr.o - -OBJS= zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o misc.o -CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \ - ${OBJS} - -# We currently allow 256k bytes for zfsboot - in practice it could be -# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr. -# -BOOT2SIZE= 262144 - -# i386 standalone support library -LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a - -zfsboot2: zfsboot.ld - @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \ - echo "$$x bytes available"; test $$x -ge 0 - ${DD} if=${.ALLSRC} of=${.TARGET} bs=${BOOT2SIZE} conv=sync - -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: - :> ${.TARGET} - -zfsboot.bin: zfsboot.out - ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET} - -zfsboot.out: ${BTXCRT} ${OBJS} - ${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32} - -SRCS= zfsboot.c - -.include <bsd.prog.mk> diff --git a/stand/i386/zfsboot/Makefile.depend b/stand/i386/zfsboot/Makefile.depend deleted file mode 100644 index 92ab022283fd..000000000000 --- a/stand/i386/zfsboot/Makefile.depend +++ /dev/null @@ -1,17 +0,0 @@ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/xlocale \ - lib/libmd \ - stand/i386/btx/btx \ - stand/i386/btx/lib \ - stand/libsa32 \ - stand/zfs32 \ - - -.include <dirdeps.mk> - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif diff --git a/stand/i386/zfsboot/zfsboot.8 b/stand/i386/zfsboot/zfsboot.8 deleted file mode 100644 index a8411bc065d0..000000000000 --- a/stand/i386/zfsboot/zfsboot.8 +++ /dev/null @@ -1,130 +0,0 @@ -.\" Copyright (c) 2014 Andriy Gapon <avg@FreeBSD.org> -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 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. -.\" -.Dd March 27, 2018 -.Dt ZFSBOOT 8 -.Os -.Sh NAME -.Nm zfsboot -.Nd bootcode for ZFS on BIOS-based computers -.Sh DESCRIPTION -.Nm -is used on BIOS-based computers to boot from a filesystem in -a ZFS pool. -.Nm -is installed in two parts on a disk or a partition used by a ZFS pool. -The first part, a single-sector starter boot block, is installed -at the beginning of the disk or partition. -The second part, a main boot block, is installed at a special offset -within the disk or partition. -Both areas are reserved by the ZFS on-disk specification for boot use. -If -.Nm -is installed in a partition, then that partition should be made -bootable using appropriate configuration and boot blocks described in -.Xr boot 8 . -.Sh BOOTING -The -.Nm -boot process is very similar to that of -.Xr gptzfsboot 8 . -One significant difference is that -.Nm -does not currently support the GPT partitioning scheme. -Thus only whole disks and MBR partitions, traditionally referred to as -slices, are probed for ZFS disk labels. -See the BUGS section in -.Xr gptzfsboot 8 -for some limitations of the MBR scheme support. -.Sh USAGE -.Nm -supports all the same prompt and configuration file arguments as -.Xr gptzfsboot 8 . -.Sh FILES -.Bl -tag -width /boot/zfsboot -compact -.It Pa /boot/zfsboot -boot code binary -.It Pa /boot.config -parameters for the boot block -.Pq optional -.It Pa /boot/config -alternative parameters for the boot block -.Pq optional -.El -.Sh EXAMPLES -.Nm -is typically installed using -.Xr dd 1 . -To install -.Nm -on the -.Pa ada0 -drive: -.Bd -literal -offset indent -dd if=/boot/zfsboot of=/dev/ada0 count=1 -dd if=/boot/zfsboot of=/dev/ada0 iseek=1 oseek=1024 -.Ed -.Pp -If the drive is currently in use, the GEOM safety will prevent writes -and must be disabled before running the above commands: -.Bd -literal -offset indent -sysctl kern.geom.debugflags=0x10 -.Ed -.Pp -.Nm -can also be installed in an MBR slice: -.Bd -literal -offset indent -gpart create -s mbr ada0 -gpart add -t freebsd ada0 -gpart bootcode -b /boot/boot0 ada0 -gpart set -a active -i 1 ada0 -dd if=/dev/zero of=/dev/ada0s1 count=2 -dd if=/boot/zfsboot of=/dev/ada0s1 count=1 -dd if=/boot/zfsboot of=/dev/ada0s1 iseek=1 oseek=1024 -.Ed -.Pp -Note that commands to create and populate a pool are not shown -in the example above. -.Sh SEE ALSO -.Xr dd 1 , -.Xr boot.config 5 , -.Xr boot 8 , -.Xr gptzfsboot 8 , -.Xr loader 8 , -.Xr zpool 8 -.Sh HISTORY -.Nm -appeared in FreeBSD 7.3. -.Sh AUTHORS -This manual page was written by -.An Andriy Gapon Aq avg@FreeBSD.org . -.Sh BUGS -Installing -.Nm -with -.Xr dd 1 -is a hack. -ZFS needs a command to properly install -.Nm -onto a ZFS-controlled disk or partition. diff --git a/stand/i386/zfsboot/zfsldr.S b/stand/i386/zfsboot/zfsldr.S deleted file mode 100644 index cd8289f952fd..000000000000 --- a/stand/i386/zfsboot/zfsldr.S +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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. - */ - -/* Memory Locations */ - .set MEM_ARG,0x900 # Arguments - .set MEM_ORG,0x7c00 # Origin - .set MEM_BUF,0x8000 # Load area - .set MEM_BTX,0x9000 # BTX start - .set MEM_JMP,0x9010 # BTX entry point - .set MEM_USR,0xa000 # Client start - .set BDA_BOOT,0x472 # Boot howto flag - -/* Partition Constants */ - .set PRT_OFF,0x1be # Partition offset - .set PRT_NUM,0x4 # Partitions - .set PRT_BSD,0xa5 # Partition type - -/* Misc. Constants */ - .set SIZ_PAG,0x1000 # Page size - .set SIZ_SEC,0x200 # Sector size - .set COPY_BLKS,0x8 # Number of blocks - # to copy for boot2 (<= 15) - .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be - # a multiple of 16 bytes - .set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS) - .globl start - .code16 - -/* - * Load the rest of zfsboot2 and BTX up, copy the parts to the right locations, - * and start it all up. - */ - -/* - * Setup the segment registers to flat addressing (segment 0) and setup the - * stack to end just below the start of our code. - */ -start: cld # String ops inc - xor %cx,%cx # Zero - mov %cx,%es # Address - mov %cx,%ds # data - mov %cx,%ss # Set up - mov $start,%sp # stack -/* - * Load the MBR and look for the first FreeBSD slice. We use the fake - * partition entry below that points to the MBR when we call read. - * The first pass looks for the first active FreeBSD slice. The - * second pass looks for the first non-active FreeBSD slice if the - * first one fails. - */ - call check_edd # Make sure EDD works - mov $part4,%si # Dummy partition - xor %eax,%eax # Read MBR - movl $MEM_BUF,%ebx # from first - call read # sector - mov $0x1,%cx # Two passes -main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table - movb $0x1,%dh # Partition -main.2: cmpb $PRT_BSD,0x4(%si) # Our partition type? - jne main.3 # No - jcxz main.5 # If second pass - testb $0x80,(%si) # Active? - jnz main.5 # Yes -main.3: add $0x10,%si # Next entry - incb %dh # Partition - cmpb $0x1+PRT_NUM,%dh # In table? - jb main.2 # Yes - dec %cx # Do two - jcxz main.1 # passes -/* - * If we get here, we didn't find any FreeBSD slices at all, so print an - * error message and die. - */ - mov $msg_part,%si # Message - jmp error # Error - -/* - * Ok, we have a slice and drive in %dx now, so use that to locate and - * load boot2. %si references the start of the slice we are looking - * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors - * starting at sector 1024 (i.e. after the two vdev labels). We don't - * have do anything fancy here to allow for an extra copy of boot1 and - * a partition table (compare to this section of the UFS bootstrap) so we - * just load it all at 0x9000. The first part of boot2 is BTX, which wants - * to run at 0x9000. The boot2.bin binary starts right after the end of BTX, - * so we have to figure out where the start of it is and then move the - * binary to 0xc000. Normally, BTX clients start at MEM_USR, or 0xa000, - * but when we use btxld to create zfsboot2, we use an entry point of - * 0x2000. That entry point is relative to MEM_USR; thus boot2.bin - * starts at 0xc000. - * - * The load area and the target area for the client overlap so we have - * to use a decrementing string move. We also play segment register - * games with the destination address for the move so that the client - * can be larger than 16k (which would overflow the zero segment since - * the client starts at 0xc000). - */ -main.5: mov %dx,MEM_ARG # Save args - mov $NSECT,%cx # Sector count - movl $1024,%eax # Offset to boot2 - mov $MEM_BTX,%ebx # Destination buffer -main.6: pushal # Save params - call read # Read disk - popal # Restore - incl %eax # Advance to - add $SIZ_SEC,%ebx # next sector - loop main.6 # If not last, read another - - mov $MEM_BTX,%bx # BTX - mov 0xa(%bx),%si # Get BTX length and set - add %bx,%si # %si to start of boot2 - dec %si # Set %ds:%si to point at the - mov %si,%ax # last byte we want to copy - shr $4,%ax # from boot2, with %si made as - add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # small as possible. - and $0xf,%si # - mov %ax,%ds # - mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at - add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # the last byte we - mov %ax,%es # want to copy boot2 into. - mov $COPY_BLKS,%bx # Copy COPY_BLKS 32k blocks -copyloop: - add $COPY_BLK_SZ,%si # Adjust %ds:%si to point at - mov %ds,%ax # the end of the next 32k to - sub $COPY_BLK_SZ/16,%ax # copy from boot2 - mov %ax,%ds - mov $COPY_BLK_SZ-1,%di # Adjust %es:%di to point at - mov %es,%ax # the end of the next 32k into - sub $COPY_BLK_SZ/16,%ax # which we want boot2 copied - mov %ax,%es - mov $COPY_BLK_SZ,%cx # Copy 32k - std - rep movsb - dec %bx - jnz copyloop - mov %cx,%ds # Reset %ds and %es - mov %cx,%es - cld # Back to increment - -/* - * Enable A20 so we can access memory above 1 meg. - * Use the zero-valued %cx as a timeout for embedded hardware which do not - * have a keyboard controller. - */ -seta20: cli # Disable interrupts -seta20.1: dec %cx # Timeout? - jz seta20.3 # Yes - inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz seta20.1 # Yes - movb $0xd1,%al # Command: Write - outb %al,$0x64 # output port -seta20.2: inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz seta20.2 # Yes - movb $0xdf,%al # Enable - outb %al,$0x60 # A20 -seta20.3: sti # Enable interrupts - - jmp start+MEM_JMP-MEM_ORG # Start BTX - - -/* - * Read a sector from the disk. Sets up an EDD packet on the stack - * and passes it to read. We assume that the destination address is - * always segment-aligned. - * - * %eax - int - LBA to read in relative to partition start - * %ebx - ptr - destination address - * %dl - byte - drive to read from - * %si - ptr - MBR partition entry - */ -read: xor %ecx,%ecx # Get - addl 0x8(%si),%eax # LBA - adc $0,%ecx - pushl %ecx # Starting absolute block - pushl %eax # block number - shr $4,%ebx # Convert to segment - push %bx # Address of - push $0 # transfer buffer - push $0x1 # Read 1 sector - push $0x10 # Size of packet - mov %sp,%si # Packet pointer - mov $0x42,%ah # BIOS: Extended - int $0x13 # read - jc read.1 # If error, fail - lea 0x10(%si),%sp # Clear stack - ret # If success, return -read.1: mov %ah,%al # Format - mov $read_err,%di # error - call hex8 # code - mov $msg_read,%si # Set the error message and - # fall through to the error - # routine -/* - * Print out the error message pointed to by %ds:(%si) followed - * by a prompt, wait for a keypress, and then reboot the machine. - */ -error: callw putstr # Display message - mov $prompt,%si # Display - callw putstr # prompt - xorb %ah,%ah # BIOS: Get - int $0x16 # keypress - movw $0x1234, BDA_BOOT # Do a warm boot - ljmp $0xffff,$0x0 # reboot the machine -/* - * Display a null-terminated string using the BIOS output. - */ -putstr.0: mov $0x7,%bx # Page:attribute - movb $0xe,%ah # BIOS: Display - int $0x10 # character -putstr: lodsb # Get char - testb %al,%al # End of string? - jne putstr.0 # No - ret # To caller -/* - * Check to see if the disk supports EDD. zfsboot requires EDD and does not - * support older C/H/S disk I/O. - */ -check_edd: cmpb $0x80,%dl # Hard drive? - jb check_edd.1 # No, fail to boot - mov $0x55aa,%bx # Magic - push %dx # Save - movb $0x41,%ah # BIOS: Check - int $0x13 # extensions present - pop %dx # Restore - jc check_edd.1 # If error, fail - cmp $0xaa55,%bx # Magic? - jne check_edd.1 # No, so fail - testb $0x1,%cl # Packet interface? - jz check_edd.1 # No, so fail - ret # EDD ok, keep booting -check_edd.1: mov $msg_chs,%si # Warn that CHS is - jmp error # unsupported and fail -/* - * AL to hex, saving the result to [EDI]. - */ -hex8: push %ax # Save - shrb $0x4,%al # Do upper - call hex8.1 # 4 - pop %ax # 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) - -/* Messages */ - -msg_chs: .asciz "CHS not supported" -msg_read: .ascii "Read error: " -read_err: .asciz "XX" -msg_part: .asciz "Boot error" - -prompt: .asciz "\r\n" - - .org PRT_OFF,0x90 - -/* Partition table */ - - .fill 0x30,0x1,0x0 -part4: .byte 0x80, 0x00, 0x01, 0x00 - .byte 0xa5, 0xfe, 0xff, 0xff - .byte 0x00, 0x00, 0x00, 0x00 - .byte 0x50, 0xc3, 0x00, 0x00 # 50000 sectors long, bleh - - .word 0xaa55 # Magic number diff --git a/stand/images/Makefile b/stand/images/Makefile index d1e7d124dfa6..2f45b989e0a7 100644 --- a/stand/images/Makefile +++ b/stand/images/Makefile @@ -1,6 +1,7 @@ .include <bsd.init.mk> -FILES+= freebsd-brand-rev.png freebsd-brand.png freebsd-logo-rev.png +FILES+= freebsd-brand-rev.png freebsd-brand.png freebsd-install-brand-rev.png \ + freebsd-logo-rev.png FILESDIR= /boot/images diff --git a/stand/images/freebsd-install-brand-rev.png b/stand/images/freebsd-install-brand-rev.png Binary files differnew file mode 100644 index 000000000000..59d173d3f8b3 --- /dev/null +++ b/stand/images/freebsd-install-brand-rev.png diff --git a/stand/kboot/include/efi.h b/stand/kboot/include/efi.h index 10368bd4a829..26a6cf8944ca 100644 --- a/stand/kboot/include/efi.h +++ b/stand/kboot/include/efi.h @@ -13,5 +13,15 @@ typedef void (*efi_map_entry_cb)(struct efi_md *, void *argp); +struct preloaded_file; + +bool efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers); +void efi_read_from_sysfs(void); +void efi_set_systbl(uint64_t tbl); void foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp); void print_efi_map(struct efi_map_header *efihdr); +void efi_bi_loadsmap(struct preloaded_file *kfp); + +extern uint32_t efi_map_size; +extern vm_paddr_t efi_map_phys_src; /* From DTB */ +extern vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */ diff --git a/stand/kboot/include/util.h b/stand/kboot/include/util.h index ca71277bc66a..dabf3d1ba9fb 100644 --- a/stand/kboot/include/util.h +++ b/stand/kboot/include/util.h @@ -6,5 +6,10 @@ #pragma once +/* dfk.c: */ +bool data_from_kernel(const char *sym, void *buf, size_t len); + +/* util.c: */ bool file2str(const char *fn, char *buffer, size_t buflen); +bool file2u32(const char *fn, uint32_t *val); bool file2u64(const char *fn, uint64_t *val); diff --git a/stand/kboot/kboot/arch/aarch64/exec.c b/stand/kboot/kboot/arch/aarch64/exec.c index 59ca4b67a4ab..df3e922dfe11 100644 --- a/stand/kboot/kboot/arch/aarch64/exec.c +++ b/stand/kboot/kboot/arch/aarch64/exec.c @@ -41,6 +41,7 @@ #include <machine/metadata.h> #include "bootstrap.h" +#include "efi.h" #include "kboot.h" #include "platform/acfreebsd.h" @@ -65,11 +66,7 @@ static int elf64_obj_exec(struct preloaded_file *amp); bool do_mem_map = false; -extern uint32_t efi_map_size; -extern vm_paddr_t efi_map_phys_src; /* From DTB */ -extern vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */ - -/* Usually provided by loader_efi.h */ +/* Usually provided by loader_efi.h -- maybe just delete? */ #ifndef EFI int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs); @@ -191,9 +188,9 @@ elf64_exec(struct preloaded_file *fp) /* * Figure out where to put it. * - * Linux does not allow us to kexec_load into any part of memory. Ask - * arch_loadaddr to resolve the first available chunk of physical memory - * where loading is possible (load_addr). + * Linux does not allow us to kexec_load into any part of memory. Find + * the first available chunk of physical memory where loading is + * possible (staging). * * The kernel is loaded at the 'base' address in continguous physical * memory. We use the 2MB in front of the kernel as a place to put our @@ -290,4 +287,3 @@ elf64_obj_exec(struct preloaded_file *fp) fp->f_name); return (ENOSYS); } - diff --git a/stand/kboot/kboot/arch/aarch64/load_addr.c b/stand/kboot/kboot/arch/aarch64/load_addr.c index 8ceb21007c45..c458adc8dd05 100644 --- a/stand/kboot/kboot/arch/aarch64/load_addr.c +++ b/stand/kboot/kboot/arch/aarch64/load_addr.c @@ -11,30 +11,18 @@ #include <libfdt.h> #include "kboot.h" -#include "bootstrap.h" #include "efi.h" -/* - * Info from dtb about the EFI system - */ -vm_paddr_t efi_systbl_phys; -struct efi_map_header *efi_map_hdr; -uint32_t efi_map_size; -vm_paddr_t efi_map_phys_src; /* From DTB */ -vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */ - static bool do_memory_from_fdt(int fd) { struct stat sb; char *buf = NULL; - int len, offset, fd2 = -1; - uint32_t sz, ver, esz, efisz; + int len, offset; + uint32_t sz, ver, esz; uint64_t mmap_pa; const uint32_t *u32p; const uint64_t *u64p; - struct efi_map_header *efihdr; - struct efi_md *map; if (fstat(fd, &sb) < 0) return false; @@ -60,7 +48,7 @@ do_memory_from_fdt(int fd) u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len); if (u64p == NULL) goto errout; - efi_systbl_phys = fdt64_to_cpu(*u64p); + efi_set_systbl(fdt64_to_cpu(*u64p)); u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len); if (u32p == NULL) goto errout; @@ -82,62 +70,8 @@ do_memory_from_fdt(int fd) printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n", ver, esz, sz, mmap_pa); - /* - * We may have no ability to read the PA that this map is in, so pass - * the address to FreeBSD via a rather odd flag entry as the first map - * so early boot can copy the memory map into this space and have the - * rest of the code cope. - */ - efisz = roundup2(sizeof(*efihdr), 16); - buf = malloc(sz + efisz); - if (buf == NULL) - return false; - efihdr = (struct efi_map_header *)buf; - map = (struct efi_md *)((uint8_t *)efihdr + efisz); - bzero(map, sz); - efihdr->memory_size = sz; - efihdr->descriptor_size = esz; - efihdr->descriptor_version = ver; - - /* - * Save EFI table. Either this will be an empty table filled in by the trampoline, - * or we'll read it below. Either way, set these two variables so we share the best - * UEFI memory map with the kernel. - */ - efi_map_hdr = efihdr; - efi_map_size = sz + efisz; - - /* - * Try to read in the actual UEFI map. - */ - fd2 = open("host:/dev/mem", O_RDONLY); - if (fd2 < 0) { - printf("Will read UEFI mem map in tramp: no /dev/mem, need CONFIG_DEVMEM=y\n"); - goto no_read; - } - if (lseek(fd2, mmap_pa, SEEK_SET) < 0) { - printf("Will read UEFI mem map in tramp: lseek failed\n"); - goto no_read; - } - len = read(fd2, map, sz); - if (len != sz) { - if (len < 0 && errno == EPERM) - printf("Will read UEFI mem map in tramp: kernel needs CONFIG_STRICT_DEVMEM=n\n"); - else - printf("Will read UEFI mem map in tramp: lean = %d errno = %d\n", len, errno); - goto no_read; - } - printf("Read UEFI mem map from physmem\n"); - efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */ - close(fd2); - printf("UEFI MAP:\n"); - print_efi_map(efihdr); - return true; /* OK, we really have the memory map */ - -no_read: - efi_map_phys_src = mmap_pa; - close(fd2); - return true; /* We can get it the trampoline */ + efi_read_from_pa(mmap_pa, sz, esz, ver); + return true; errout: free(buf); @@ -150,22 +84,32 @@ enumerate_memory_arch(void) int fd = -1; bool rv = false; + /* + * FDT publishes the parameters for the memory table in a series of + * nodes in the DTB. One of them is the physical address for the memory + * table. Try to open the fdt nblob to find this information if we can + * and try to grab things from memory. If we return rv == TRUE then + * we found it. The global efi_map_phys_src is set != 0 when we know + * the PA but can't read it. + */ fd = open("host:/sys/firmware/fdt", O_RDONLY); if (fd != -1) { rv = do_memory_from_fdt(fd); close(fd); - /* - * So, we have physaddr to the memory table. However, we can't - * open /dev/mem on some platforms to get the actual table. So - * we have to fall through to get it from /proc/iomem. - */ } + + /* + * One would think that one could use the raw EFI map to find memory + * that's free to boot the kernel with. However, Linux reserves some + * areas that it needs to properly. I'm not sure if the printf should be + * a panic, but for now, so I can debug (maybe at the loader prompt), + * I'm printing and carrying on. + */ if (!rv) { printf("Could not obtain UEFI memory tables, expect failure\n"); } populate_avail_from_iomem(); - print_avail(); return true; @@ -181,32 +125,19 @@ kboot_get_phys_load_segment(void) if (s != 0) return (s); + print_avail(); s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM); + printf("KBOOT GET PHYS Using %#llx\n", (long long)s); if (s != 0) return (s); s = 0x40000000 | 0x4200000; /* should never get here */ - printf("Falling back to crazy address %#lx\n", s); + /* XXX PANIC? XXX */ + printf("Falling back to the crazy address %#lx which works in qemu\n", s); return (s); } void bi_loadsmap(struct preloaded_file *kfp) { - - /* - * Make a note of a systbl. This is nearly mandatory on AARCH64. - */ - if (efi_systbl_phys) - file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys); - - /* - * If we have efi_map_hdr, then it's a pointer to the PA where this - * memory map lives. The trampoline code will copy it over. If we don't - * have it, we use whatever we found in /proc/iomap. - */ - if (efi_map_hdr != NULL) { - file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr); - return; - } - panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n"); + efi_bi_loadsmap(kfp); } diff --git a/stand/kboot/kboot/arch/aarch64/tramp.S b/stand/kboot/kboot/arch/aarch64/tramp.S index 32616f239c50..c0004006796d 100644 --- a/stand/kboot/kboot/arch/aarch64/tramp.S +++ b/stand/kboot/kboot/arch/aarch64/tramp.S @@ -8,7 +8,7 @@ * This is the trampoline that starts the FreeBSD kernel. Since the Linux kernel * calls this routine with no args, and has a different environment than the boot * loader provides and that the kernel expects, this code is responsible for setting - * all that up and calling the normal kernel entry point. It's analogous ot the + * all that up and calling the normal kernel entry point. It's analogous to the * "purgatory" code in the linux kernel. Details about these operations are * contained in comments below. On aarch64, the kernel will start all the APs so * we don't have to worry about them here. @@ -99,3 +99,5 @@ tramp_size: .globl tramp_data_offset tramp_data_offset: .long trampoline_data-tramp + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/kboot/arch/amd64/amd64_tramp.S b/stand/kboot/kboot/arch/amd64/amd64_tramp.S index b95e99cbaf0f..d3b2d5ecaf77 100644 --- a/stand/kboot/kboot/arch/amd64/amd64_tramp.S +++ b/stand/kboot/kboot/arch/amd64/amd64_tramp.S @@ -38,6 +38,10 @@ * store them here. This is constructed to be a useful stack: * * struct trampoline_data { + * // %rsp points here on start and we pop the args off and then retq to 'entry' + * uint64_t memmap_src; // Linux-provided memory map PA + * uint64_t memmap_dst; // Module data copy PA + * uint64_t memmap_len; // Length to copy * uint64_t pt4; // Page table address to pop * uint64_t entry; // return address to jump to kernel * uint32_t fill1; // 0 @@ -47,33 +51,52 @@ * }; * * loader.kboot will construct a stack that btext expects, which is arguments on - * the stack, not in registers, and these args are 32-bit not 64 + * the stack, not in registers, and these args are 32-bit not 64. The extra stuff + * is data the trampoline code consumes. * * Processor is already in long mode when we're called, paging is enabled and * boot loader loads things such that: * - kernel mapped at KERNBASE, aligned to 2MB, below 4GB, contiguous memory + * - %cr3 tells us our PA later in boot, so we install it before jumping + * to the kernel. * - there is a 2M hole at KERNBASE (KERNSTART = KERNBASE + 2M) * - kernel is mapped with 2M superpages * - The kernel, modules and metadata is in first 4GB which is unity mapped * - There's additional memory after loader provided data for early allocations * - * Unlike EFI, we don't support copying the staging area. We tell Linux to land - * the kernel in its final location with the needed alignment, etc. We copy the - * trampoline code to 1MB offset above KERNBASE since that memory is otherwise - * free and safely above the lower 1MB swamp we inherited from IBM PC, though - * this code makes no assumptions about where that might. + * Unlike coming directly from loader.efi, we don't support copying the staging + * area. We tell Linux to land the kernel in its final location with the needed + * alignment, etc. We copy the trampoline code to 1MB offset above KERNBASE + * since that memory is otherwise free and safely above the lower 1MB swamp we + * inherited from IBM PC, though this code makes no assumptions about where that + * might be. * - * Thus, the trampoline just needs to set %rsp to that stack pop the %cr3 value, - * set it and then retq to jump to the kernel with its stack args filled in. - * Since the handoff to this code used to be from 32-bit code, it uses the i386 - * calling conventions which put the arguments on the stack. The kernel's btext - * routine expects this setup. + * Thus, the trampoline just needs to set %rsp to that stack pop the systab + * patch value, pop the %cr3 value, set it and then retq to jump to the kernel + * with its stack args filled in. Since the handoff to this code used to be + * from 32-bit code, it uses the i386 calling conventions which put the + * arguments on the stack. The kernel's btext routine expects this setup. */ + .text .globl tramp tramp: cli /* Make sure we don't get interrupted. */ - leaq tramp_pt4(%rip), %rsp /* Setup our pre-filled-in stack */ + cld /* Copy in a sane direction */ + leaq stack_start(%rip), %rsp /* Setup our pre-filled-in stack */ + + /* + * If we have a EFI memory map, copy it over. These data are always + * on the stack, so we pop them all off before testing to skip the copy. + */ + popq %rsi /* memmap_src */ + popq %rdi /* memmap_dst */ + popq %rcx /* memmap_size */ + testq %rsi, %rsi + je no_map_copy + rep movsb /* Make the copy */ + +no_map_copy: popq %rax /* Pop off the PT4 ptr for %cr3 */ movq %rax, %cr3 /* set the page table */ retq /* Return addr and args already on stack */ @@ -84,6 +107,13 @@ tramp: */ .p2align 3 /* Stack has to be 8 byte aligned */ trampoline_data: +stack_start: /* %rsp at start. */ +tramp_memmap_src: + .quad 0 /* SRC PA (data from Linux) */ +tramp_memmap_dst: + .quad 0 /* DST PA (data to FreeBSD's metadata */ +tramp_memmap_len: + .quad 0 /* Length */ tramp_pt4: .quad 0 /* New %cr3 value */ tramp_entry: .quad 0 /* Entry to kernel (btext) */ /* %rsp points here on entry to amd64 kernel's btext */ @@ -105,3 +135,5 @@ tramp_size: tramp_data_offset: .long trampoline_data-tramp .size tramp_data_offset, 4 + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/kboot/arch/amd64/elf64_freebsd.c b/stand/kboot/kboot/arch/amd64/elf64_freebsd.c index 495c4c0b320e..576839e29734 100644 --- a/stand/kboot/kboot/arch/amd64/elf64_freebsd.c +++ b/stand/kboot/kboot/arch/amd64/elf64_freebsd.c @@ -44,6 +44,7 @@ #include "bootstrap.h" #include "kboot.h" +#include "efi.h" #include "platform/acfreebsd.h" #include "acconfig.h" @@ -97,13 +98,19 @@ struct file_format *file_formats[] = { #ifndef EFI /* - * We create the stack that we want. We have the address of the page tables - * we make on top (so we pop that off and set %cr3). We have the entry point - * to the kernel (which retq pops off) This leaves the stack that the btext - * wants: offset 4 is modulep and offset8 is kernend, with the filler bytes - * to keep this aligned. This makes the trampoline very simple. + * We create the stack that we want. We store any memory map table that we have + * top copy (the metadata has already been filled in). We pop these args off and + * copy if neeed be. Then, we have the address of the page tables we make on top + * (so we pop that off and set %cr3). We have the entry point to the kernel + * (which retq pops off) This leaves the stack that the btext wants: offset 4 is + * modulep and offset8 is kernend, with the filler bytes to keep this + * aligned. This also makes the trampoline very simple: pop some args, maybe copy + * pop the page table and then return into btext as defined in the kernel. */ struct trampoline_data { + uint64_t memmap_src; // Linux-provided memory map PA + uint64_t memmap_dst; // Module data copy PA + uint64_t memmap_len; // Length to copy uint64_t pt4; // Page table address to pop uint64_t entry; // return address to jump to kernel uint32_t fill1; // 0 @@ -111,7 +118,7 @@ struct trampoline_data { uint32_t kernend; // 8 kernel end uint32_t fill2; // 12 }; -_Static_assert(sizeof(struct trampoline_data) == 32, "Bad size for trampoline data"); +_Static_assert(sizeof(struct trampoline_data) == 56, "Bad size for trampoline data"); #endif static pml4_entry_t *PT4; @@ -171,9 +178,9 @@ elf64_exec(struct preloaded_file *fp) /* * Figure out where to put it. * - * Linux does not allow to do kexec_load into any part of memory. Ask - * arch_loadaddr to resolve the first available chunk of physical memory - * where loading is possible (load_addr). + * Linux does not allow us to do kexec_load into any part of memory. Ask + * kboot_get_phys_load_segment to resolve the first available chunk of + * physical memory where loading is possible (staging). * * The kernel is loaded at the 'base' address in continguous physical * pages (using 2MB super pages). The first such page is unused by the @@ -420,8 +427,24 @@ elf64_exec(struct preloaded_file *fp) PT4, ehdr->e_entry); #else trampoline_data = (void *)trampoline + tramp_data_offset; - trampoline_data->entry = ehdr->e_entry; - trampoline_data->pt4 = trampolinebase + LOADER_PAGE_SIZE; + trampoline_data->entry = ehdr->e_entry; /* VA since we start MMU with KERNBASE, etc */ + if (efi_map_phys_src != 0) { + md = file_findmetadata(fp, MODINFOMD_EFI_MAP); + if (md == NULL || md->md_addr == 0) { + printf("Need to copy EFI MAP, but EFI MAP not found. %p\n", md); + } else { + printf("Metadata EFI map loaded at VA %lx\n", md->md_addr); + efi_map_phys_dst = md->md_addr + staging + /* md_addr is taging relative */ + roundup2(sizeof(struct efi_map_header), 16); /* Skip header */ + trampoline_data->memmap_src = efi_map_phys_src; + trampoline_data->memmap_dst = efi_map_phys_dst; + trampoline_data->memmap_len = efi_map_size - roundup2(sizeof(struct efi_map_header), 16); + printf("Copying UEFI Memory Map data from %#lx to %#lx %ld bytes\n", + trampoline_data->memmap_src, + trampoline_data->memmap_dst, + trampoline_data->memmap_len); + } + } /* * So we compute the VA of the module data by modulep + KERNBASE.... * need to make sure that that address is mapped right. We calculate @@ -429,6 +452,7 @@ elf64_exec(struct preloaded_file *fp) * calculated with a phyaddr of "kernend + PA(PT_u0[1])"), so we better * make sure we're not overwriting the last 2MB of the kernel :). */ + trampoline_data->pt4 = trampolinebase + LOADER_PAGE_SIZE; trampoline_data->modulep = modulep; /* Offset from KERNBASE */ trampoline_data->kernend = kernend; /* Offset from the load address */ trampoline_data->fill1 = trampoline_data->fill2 = 0; diff --git a/stand/kboot/kboot/arch/amd64/load_addr.c b/stand/kboot/kboot/arch/amd64/load_addr.c index 4bd2a19dab48..8f4414d32342 100644 --- a/stand/kboot/kboot/arch/amd64/load_addr.c +++ b/stand/kboot/kboot/arch/amd64/load_addr.c @@ -29,153 +29,110 @@ #include "stand.h" #include "host_syscall.h" +#include "efi.h" #include "kboot.h" #include "bootstrap.h" -/* Refactor when we do arm64 */ - -enum types { - system_ram = 1, - acpi_tables, - acpi_nv_storage, - unusable, - persistent_old, - persistent, - soft_reserved, - reserved, -}; - -struct kv -{ - uint64_t type; - char * name; -} str2type_kv[] = { - { system_ram, "System RAM" }, - { acpi_tables, "ACPI Tables" }, - { acpi_nv_storage, "ACPI Non-volatile Storage" }, - { unusable, "Unusable memory" }, - { persistent_old, "Persistent Memory (legacy)" }, - { persistent, "Persistent Memory" }, - { soft_reserved, "Soft Reserved" }, - { reserved, "reserved" }, - { 0, NULL }, -}; - -#define MEMMAP "/sys/firmware/memmap" - -static struct memory_segments segs[64]; /* make dynamic later */ -static int nr_seg; - -static bool -str2type(struct kv *kv, const char *buf, uint64_t *value) -{ - while (kv->name != NULL) { - if (strcmp(kv->name, buf) == 0) { - *value = kv->type; - return true; - } - kv++; - } +/* + * Abbreviated x86 Linux struct boot_param for the so-called zero-page. + * We have to use this to get systab and memmap since neither of those + * are exposed in a sane way. We only define what we need and pad for + * everything else to minimize cross-coupling. + * + * Transcribed in FreeBSD-ese from Linux's asm/bootparam.h for x86 as of + * 6.15, but these details haven't changed in a long time. + */ - return false; -} +struct linux_efi_info { + uint32_t efi_loader_signature; /* 0x00 */ + uint32_t efi_systab; /* 0x04 */ + uint32_t efi_memdesc_size; /* 0x08 */ + uint32_t efi_memdesc_version; /* 0x0c */ + uint32_t efi_memmap; /* 0x10 */ + uint32_t efi_memmap_size; /* 0x14 */ + uint32_t efi_systab_hi; /* 0x18 */ + uint32_t efi_memmap_hi; /* 0x1c */ +} __packed; + +struct linux_boot_params { + uint8_t _pad1[0x1c0]; /* 0x000 */ + struct linux_efi_info efi_info; /* 0x1c0 */ + uint8_t _pad2[0x1000 - 0x1c0 - sizeof(struct linux_efi_info)]; /* 0x1e0 */ +} __packed; /* Total size 4k, the page size on x86 */ bool enumerate_memory_arch(void) { - int n; - char name[MAXPATHLEN]; - char buf[80]; - - for (n = 0; n < nitems(segs); n++) { - snprintf(name, sizeof(name), "%s/%d/start", MEMMAP, n); - if (!file2u64(name, &segs[n].start)) - break; - snprintf(name, sizeof(name), "%s/%d/end", MEMMAP, n); - if (!file2u64(name, &segs[n].end)) - break; - snprintf(name, sizeof(name), "%s/%d/type", MEMMAP, n); - if (!file2str(name, buf, sizeof(buf))) - break; - if (!str2type(str2type_kv, buf, &segs[n].type)) - break; + struct linux_boot_params bp; + + /* + * Sadly, there's no properly exported data for the EFI memory map nor + * the system table. systab is passed in from the original boot loader. + * memmap is obtained from boot time services (which are long gone) and + * then modified and passed to SetVirtualAddressMap. Even though the + * latter is in runtime services, it can only be called once and Linux + * has already called it. So unless we can dig all this out from the + * Linux kernel, there's no other wy to get it. A proper way would be to + * publish these in /sys/firmware/efi, but that's not done yet. We can + * only get the runtime subset and can't get systbl at all from today's + * (6.15) Linux kernel. Linux's pandora boot loader will copy this same + * information when it calls the new kernel, but since we don't use the + * bzImage kexec vector, we have to harvest it here. + */ + if (data_from_kernel("boot_params", &bp, sizeof(bp))) { + uint64_t systbl, memmap; + + systbl = (uint64_t)bp.efi_info.efi_systab_hi << 32 | + bp.efi_info.efi_systab; + memmap = (uint64_t)bp.efi_info.efi_memmap_hi << 32 | + bp.efi_info.efi_memmap; + + efi_set_systbl(systbl); + efi_read_from_pa(memmap, bp.efi_info.efi_memmap_size, + bp.efi_info.efi_memdesc_size, bp.efi_info.efi_memdesc_version); + printf("UEFI SYSTAB PA: %#lx\n", systbl); + printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n", + bp.efi_info.efi_memdesc_version, bp.efi_info.efi_memdesc_size, + bp.efi_info.efi_memmap_size, memmap); } - - nr_seg = n; - - return true; -} - -#define BAD_SEG ~0ULL - -#define SZ(s) (((s).end - (s).start) + 1) - -static uint64_t -find_ram(struct memory_segments *segs, int nr_seg, uint64_t minpa, uint64_t align, - uint64_t sz, uint64_t maxpa) -{ - uint64_t start; - - printf("minpa %#jx align %#jx sz %#jx maxpa %#jx\n", - (uintmax_t)minpa, - (uintmax_t)align, - (uintmax_t)sz, - (uintmax_t)maxpa); - /* XXX assume segs are sorted in numeric order -- assumed not ensured */ - for (int i = 0; i < nr_seg; i++) { - if (segs[i].type != system_ram || - SZ(segs[i]) < sz || - minpa + sz > segs[i].end || - maxpa < segs[i].start) - continue; - start = roundup(segs[i].start, align); - if (start < minpa) /* Too small, round up and try again */ - start = (roundup(minpa, align)); - if (start + sz > segs[i].end) /* doesn't fit in seg */ - continue; - if (start > maxpa || /* Over the edge */ - start + sz > maxpa) /* on the edge */ - break; /* No hope to continue */ - return start; + /* + * So, we can't use the EFI map for this, so we have to fall back to + * the proc iomem stuff to at least get started... + */ + if (!populate_avail_from_iomem()) { + printf("Populate from avail also failed.\n"); + return (false); + } else { + printf("Populate worked...\n"); } - - return BAD_SEG; + print_avail(); + return (true); } +/* XXX refactor with aarch64 */ uint64_t kboot_get_phys_load_segment(void) { - static uint64_t base_seg = BAD_SEG; - - if (base_seg != BAD_SEG) - return (base_seg); - - if (nr_seg > 0) - base_seg = find_ram(segs, nr_seg, 2ULL << 20, 2ULL << 20, - 64ULL << 20, 4ULL << 30); - if (base_seg == BAD_SEG) { - /* XXX Should fall back to using /proc/iomem maybe? */ - /* XXX PUNT UNTIL I NEED SOMETHING BETTER */ - base_seg = 300ULL * (1 << 20); - } - return (base_seg); +#define HOLE_SIZE (64ul << 20) +#define KERN_ALIGN (2ul << 20) + static uint64_t s = 0; + + if (s != 0) + return (s); + + print_avail(); + s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM); + printf("KBOOT GET PHYS Using %#llx\n", (long long)s); + if (s != 0) + return (s); + s = 0x40000000 | 0x4200000; /* should never get here */ + /* XXX PANIC? XXX */ + printf("Falling back to the crazy address %#lx which works in qemu\n", s); + return (s); } void bi_loadsmap(struct preloaded_file *kfp) { - struct bios_smap smap[32], *sm; - struct memory_segments *s; - int smapnum, len; - - for (smapnum = 0; smapnum < min(32, nr_seg); smapnum++) { - sm = &smap[smapnum]; - s = &segs[smapnum]; - sm->base = s->start; - sm->length = s->end - s->start + 1; - sm->type = SMAP_TYPE_MEMORY; - } - - len = smapnum * sizeof(struct bios_smap); - file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]); + efi_bi_loadsmap(kfp); } diff --git a/stand/kboot/kboot/arch/powerpc64/kerneltramp.S b/stand/kboot/kboot/arch/powerpc64/kerneltramp.S index 211a6e474d2a..e9678dc02e72 100644 --- a/stand/kboot/kboot/arch/powerpc64/kerneltramp.S +++ b/stand/kboot/kboot/arch/powerpc64/kerneltramp.S @@ -99,3 +99,5 @@ endkerneltramp: .data CNAME(szkerneltramp): .long endkerneltramp - CNAME(kerneltramp) + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c b/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c index ffa00e151661..ae398e357df2 100644 --- a/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c +++ b/stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c @@ -89,21 +89,18 @@ ppc64_elf_exec(struct preloaded_file *fp) /* * Figure out where to put it. * - * Linux does not allow to do kexec_load into - * any part of memory. Ask arch_loadaddr to - * resolve the first available chunk of physical - * memory where loading is possible (load_addr). + * Linux does not allow us to do kexec_load into any part of memory. Ask + * kboot_get_phys_load_segment to resolve the first available chunk of + * physical memory where loading is possible (load_addr). * - * Memory organization is shown below. - * It is assumed, that text segment offset of - * kernel ELF (KERNPHYSADDR) is non-zero, - * which is true for PPC/PPC64 architectures, - * where default is 0x100000. + * Memory organization is shown below. It is assumed, that text segment + * offset of kernel ELF (KERNPHYSADDR) is non-zero, which is true for + * PPC/PPC64 architectures, where default is 0x100000. * * load_addr: trampoline code * load_addr + KERNPHYSADDR: kernel text segment */ - trampolinebase = archsw.arch_loadaddr(LOAD_RAW, NULL, 0); + trampolinebase = kboot_get_phys_load_segment(); printf("Load address at %#jx\n", (uintmax_t)trampolinebase); printf("Relocation offset is %#jx\n", (uintmax_t)elf64_relocation_offset); diff --git a/stand/kboot/kboot/main.c b/stand/kboot/kboot/main.c index 65f7b77f1ace..4a136b42a4a1 100644 --- a/stand/kboot/kboot/main.c +++ b/stand/kboot/kboot/main.c @@ -37,9 +37,6 @@ #include "stand.h" #include <smbios.h> -struct arch_switch archsw; -extern void *_end; - 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); @@ -47,11 +44,34 @@ ssize_t kboot_readin(readin_handle_t fd, vm_offset_t dest, const size_t len); int kboot_autoload(void); static void kboot_zfs_probe(void); +struct arch_switch archsw = { + .arch_getdev = kboot_getdev, + .arch_copyin = kboot_copyin, + .arch_copyout = kboot_copyout, + .arch_readin = kboot_readin, + .arch_autoload = kboot_autoload, + .arch_zfs_probe = kboot_zfs_probe, +}; + extern int command_fdt_internal(int argc, char *argv[]); +/* + * On amd64, KERNSTART is where the first actual kernel page is mapped, after + * the compatibility mapping. We reserve 2MB at the start of the address space + * for the page tables, etc, and so need to offset this there (and only there). + * The loader needs to know about this so we can pad everything to the proper + * place in PA. Ideally, we'd include vmparam.h to figure this out, but the + * macros it uses are not easily available in this compile environment, so we + * hard code that knowledge here. + */ +#if defined(__amd64__) +#define KERN_PADDING (2 << 20) +#else +#define KERN_PADDING 0 +#endif + #define PA_INVAL (vm_offset_t)-1 static vm_offset_t pa_start = PA_INVAL; -static vm_offset_t padding; static vm_offset_t offset; static uint64_t commit_limit; @@ -209,6 +229,7 @@ static struct mapping uintptr_t pa; caddr_t va; } map[MAX_MAP]; +static bool smbios_mmap_file; static int smbios_fd; static int nmap; @@ -218,12 +239,17 @@ caddr_t ptov(uintptr_t pa) uintptr_t pa2; struct mapping *m = map; - pa2 = rounddown(pa, PAGE); + if (smbios_mmap_file) + pa2 = rounddown(pa, PAGE); + else + pa2 = pa; for (int i = 0; i < nmap; i++, m++) { if (m->pa == pa2) { return (m->va + pa - m->pa); } } + if (!smbios_mmap_file) + panic("Out of bounds smbios access"); if (nmap == MAX_MAP) panic("Too many maps for smbios"); @@ -278,6 +304,7 @@ static void find_smbios(void) { char buf[40]; + void *dmi_data; uintptr_t pa; caddr_t va; @@ -286,17 +313,47 @@ find_smbios(void) if (pa == 0) return; + dmi_data = NULL; + smbios_fd = host_open("/sys/firmware/dmi/tables/DMI", O_RDONLY, 0); + if (smbios_fd >= 0) { + struct host_kstat sb; + struct mapping *m; + + if (host_fstat(smbios_fd, &sb) < 0) { + host_close(smbios_fd); + goto try_dev_mem; + } + + dmi_data = malloc(sb.st_size); + if (dmi_data == NULL) { + host_close(smbios_fd); + goto try_dev_mem; + } + + host_read(smbios_fd, dmi_data, sb.st_size); + + m = &map[nmap++]; + m->pa = pa; + m->va = dmi_data; + smbios_mmap_file = false; + } else { +try_dev_mem: + smbios_fd = host_open("/dev/mem", O_RDONLY, 0); + if (smbios_fd < 0) { + printf("Can't open /sys/firmware/dmi/tables/DMI or " + "/dev/mem to read smbios\n"); + return; + } + smbios_mmap_file = true; + } snprintf(buf, sizeof(buf), "%#jx", (uintmax_t)pa); setenv("hint.smbios.0.mem", buf, 1); - smbios_fd = host_open("/dev/mem", O_RDONLY, 0); - if (smbios_fd < 0) { - printf("Can't open /dev/mem to read smbios\n"); - return; - } + va = ptov(pa); printf("Start of smbios at pa %p va %p\n", (void *)pa, va); smbios_detect(va); smbios_cleanup(); + free(dmi_data); host_close(smbios_fd); } @@ -332,13 +389,6 @@ main(int argc, const char **argv) const size_t heapsize = 64*1024*1024; const char *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_zfs_probe = kboot_zfs_probe; - /* Give us a sane world if we're running as init */ do_init(); @@ -386,6 +436,8 @@ main(int argc, const char **argv) bootdev = getenv("currdev"); } #endif + if (bootdev == NULL) + bootdev = "host:/"; if (bootdev != NULL) { /* * Otherwise, honor what's on the command line. If we've been @@ -514,15 +566,13 @@ kboot_copyin(const void *src, vm_offset_t dest, const size_t len) if (pa_start == PA_INVAL) { pa_start = kboot_get_phys_load_segment(); -// padding = 2 << 20; /* XXX amd64: revisit this when we make it work */ - padding = 0; offset = dest; get_phys_buffer(pa_start, len, &destbuf); } remainder = len; do { - segsize = get_phys_buffer(dest + pa_start + padding - offset, remainder, &destbuf); + segsize = get_phys_buffer(dest + pa_start + KERN_PADDING - offset, remainder, &destbuf); bcopy(src, destbuf, segsize); remainder -= segsize; src += segsize; @@ -540,7 +590,7 @@ kboot_copyout(vm_offset_t src, void *dest, const size_t len) remainder = len; do { - segsize = get_phys_buffer(src + pa_start + padding - offset, remainder, &srcbuf); + segsize = get_phys_buffer(src + pa_start + KERN_PADDING - offset, remainder, &srcbuf); bcopy(srcbuf, dest, segsize); remainder -= segsize; src += segsize; @@ -642,3 +692,15 @@ command_fdt(int argc, char *argv[]) COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif + +/* + * Support quitting. + */ +static int +command_quit(int argc, char *argv[]) +{ + exit(0); + return (CMD_OK); +} + +COMMAND_SET(quit, "quit", "exit the program", command_quit); diff --git a/stand/kboot/libkboot/Makefile b/stand/kboot/libkboot/Makefile index e23ae9bb9215..1c91636cc69b 100644 --- a/stand/kboot/libkboot/Makefile +++ b/stand/kboot/libkboot/Makefile @@ -5,8 +5,10 @@ WARNS?= 4 .PATH: ${.CURDIR}/arch/${MACHINE_ARCH} CFLAGS+=-I${.CURDIR} -I${.CURDIR}/arch/${MACHINE_ARCH} +CFLAGS+=-I${LDRSRC} SRCS= crt1.c +SRCS+= dfk.c SRCS+= host_syscall.S SRCS+= host_syscalls.c SRCS+= seg.c diff --git a/stand/kboot/libkboot/arch/aarch64/host_syscall.S b/stand/kboot/libkboot/arch/aarch64/host_syscall.S index db3ecf0f885d..3b1c345f2cf6 100644 --- a/stand/kboot/libkboot/arch/aarch64/host_syscall.S +++ b/stand/kboot/libkboot/arch/aarch64/host_syscall.S @@ -16,3 +16,5 @@ ENTRY(host_syscall) ret /* Note: We're exposing the raw return value to the caller */ END(host_syscall) + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/libkboot/arch/amd64/host_syscall.S b/stand/kboot/libkboot/arch/amd64/host_syscall.S index 5bf0fca0cec1..0869bfe245f6 100644 --- a/stand/kboot/libkboot/arch/amd64/host_syscall.S +++ b/stand/kboot/libkboot/arch/amd64/host_syscall.S @@ -27,3 +27,5 @@ ENTRY(host_syscall) ret /* Note: We're exposing the raw return value to the caller */ END(host_syscall) + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/libkboot/arch/powerpc64/host_syscall.S b/stand/kboot/libkboot/arch/powerpc64/host_syscall.S index f9108065ebfa..84fde2041704 100644 --- a/stand/kboot/libkboot/arch/powerpc64/host_syscall.S +++ b/stand/kboot/libkboot/arch/powerpc64/host_syscall.S @@ -30,3 +30,5 @@ ENTRY(host_syscall) blr /* Note: We're exposing the raw return value to the caller */ END(host_syscall) + + .section .note.GNU-stack,"",%progbits diff --git a/stand/kboot/libkboot/crt1.c b/stand/kboot/libkboot/crt1.c index 2fbe00262da7..67ddacccfd26 100644 --- a/stand/kboot/libkboot/crt1.c +++ b/stand/kboot/libkboot/crt1.c @@ -57,6 +57,8 @@ extern int main(int, const char **, char **); #include "start_arch.h" +void *stack_upper_limit; + void _start_c(long *p) { @@ -64,6 +66,7 @@ _start_c(long *p) const char **argv; char **envp; + stack_upper_limit = p; /* Save the upper limit of call stack */ argc = p[0]; argv = (const char **)(p + 1); envp = (char **)argv + argc + 1; diff --git a/stand/kboot/libkboot/dfk.c b/stand/kboot/libkboot/dfk.c new file mode 100644 index 000000000000..09f4512f5c99 --- /dev/null +++ b/stand/kboot/libkboot/dfk.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2025 Netflix, Inc + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Common macros to allow compiling this as a Linux binary or in libsa. + */ +#ifdef _STANDALONE +#include "stand.h" +/* Not ideal, but these are missing in libsa */ +#define perror(msg) printf("ERROR %d: %s\n", errno, msg) +#define fprintf(x, ...) printf( __VA_ARGS__ ) +#include <machine/elf.h> +#include <sys/param.h> +#include "util.h" +#else +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <asm/bootparam.h> + +#define PAGE_SIZE 4096 +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#define ELF_TARG_DATA ELFDATA2LSB +#endif + +#define KCORE_PATH "/proc/kcore" +#define KALLSYMS_PATH "/proc/kallsyms" + +struct elf_file +{ + uint8_t buf[PAGE_SIZE]; + int fd; +}; + +// All the line_buffer stuff can be replaced by fgetstr() + +struct line_buffer +{ + int fd; + char buf[PAGE_SIZE]; + char *pos; + char *eos; +}; + +/* + * We just assume we have to fill if we are called. + */ +static bool +lb_fill(struct line_buffer *lb) +{ + ssize_t rv; + + lb->pos = lb->eos = lb->buf; // Reset to no data condition + rv = read(lb->fd, lb->buf, sizeof(lb->buf)); + if (rv <= 0) + return (false); + lb->pos = lb->buf; + lb->eos = lb->buf + rv; + return (true); +} + +static bool +lb_fini(struct line_buffer *lb) +{ + close(lb->fd); + return (true); +} + +static bool +lb_init(struct line_buffer *lb, const char *fn) +{ + lb->fd = open(fn, O_RDONLY); + if (lb->fd == -1) + return (false); + lb->pos = lb->eos = lb->buf; + if (!lb_fill(lb)) { + lb_fini(lb); + return (false); + } + return (true); +} + +// True -> data returned +// False -> EOF / ERROR w/o data +static bool +lb_1line(struct line_buffer *lb, char *buffer, size_t buflen) +{ + char *bufeos = buffer + buflen - 1; // point at byte for NUL at eos + char *walker = buffer; + + while (walker < bufeos) { // < to exclude space for NUL + if (lb->pos >= lb->eos) { // Refill empty buffer + if (!lb_fill(lb)) { // Hit EOF / error + if (walker > buffer) // Have data? return it + break; + // No data, signal EOF/Error + return (false); + } + } + *walker = *lb->pos++; + if (*walker == '\n') + break; + walker++; + } + /* + * We know walker <= bufeos, so NUL will fit. + */ + *++walker = '\0'; + return (true); +} + +/* + * Scan /proc/kallsyms to find @symbol and return the value it finds there. + */ +unsigned long +symbol_addr(const char *symbol) +{ + struct line_buffer lb; + unsigned long addr; + char line[256]; + + if (!lb_init(&lb, KALLSYMS_PATH)) + return (0); + while (lb_1line(&lb, line, sizeof(line))) { + char *val, *name, *x, t; + + /* + * Parse lines of the form + * val<sp>t<sp>name\n + * looking for one with t in [dDbB] (so data) name == symbol, + * skipping lines that don't match the pattern. + */ + val = line; + x = strchr(val, ' '); + if (x == NULL) + continue; /* No 1st <sp> */ + *x++ = '\0'; + t = *x++; + if (strchr("dDbB", t) == NULL) + continue; /* Only data types */ + if (*x++ != ' ') + continue; /* No 2nd <sp> */ + name = x; + x = strchr(x, '\n'); + if (x == NULL) + continue; /* No traling newline */ + *x++ = '\0'; + if (strcmp(name, symbol) == 0) { + unsigned long v; + char *eop = NULL; + lb_fini(&lb); + v = strtoul(val, &eop, 16); + if (*eop == '\0') + return (v); + return (0); /* PARSE ERROR -- what to do? */ + } + /* No match, try next */ + } + + lb_fini(&lb); + return (0); +} + +/* + * Parse /proc/kcore to find if we can get the data for @len bytes that are + * mapped in the kernel at VA @addr. It's a CORE file in ELF format that the + * kernel exports for the 'safe' areas to touch. We can read random kernel + * varaibles, but we can't read arbitrary addresses since it doesn't export + * the direct map. + */ +bool +read_at_address(unsigned long addr, void *buf, size_t len) +{ + struct elf_file ef; + Elf64_Ehdr *hdr; + Elf64_Phdr *phdr; + ssize_t rv; + + bzero(&ef, sizeof(ef)); + ef.fd = open(KCORE_PATH, O_RDONLY); + if (ef.fd == -1) { + perror("open " KCORE_PATH "\n"); + return (false); + } + + /* + * Read in the first page. ELF files have a header that says how many + * sections are in the file, whre they are, etc. All the Phdr are in the + * first page. Read it, verify the headers, then loop through these Phdr + * to find the address where addr is mapped to read it. + */ + rv = read(ef.fd, ef.buf, sizeof(ef.buf)); + if (rv != sizeof(ef.buf)) { + perror("short hdr read\n"); + close(ef.fd); + return (false); + } + hdr = (Elf64_Ehdr *)&ef.buf; + if (!IS_ELF(*hdr)) { + fprintf(stderr, "Not Elf\n"); + close(ef.fd); + return (false); + } + if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + hdr->e_ident[EI_DATA] != ELF_TARG_DATA || + hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + hdr->e_version != EV_CURRENT || + hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ + hdr->e_type != ET_CORE) { + fprintf(stderr, "Not what I expect\n"); + close(ef.fd); + return (false); + } + + phdr = (Elf64_Phdr *)(ef.buf + hdr->e_phoff); + for (int i = 0; i < hdr->e_phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + if (addr < phdr[i].p_vaddr || + addr >= phdr[i].p_vaddr + phdr[i].p_filesz) + continue; + lseek(ef.fd, (off_t)phdr[i].p_offset + addr - phdr[i].p_vaddr, + SEEK_SET); + rv = read(ef.fd, buf, len); + if (rv != len) + perror("Can't read buffer\n"); + close(ef.fd); + return (rv == len); + } + + close(ef.fd); + return (false); +} + +/* + * Read a value from the Linux kernel. We lookup @sym and read @len bytes into + * @buf. Returns true if we got it, false on an error. + */ +bool +data_from_kernel(const char *sym, void *buf, size_t len) +{ + unsigned long addr; + + addr = symbol_addr(sym); + if (addr == 0) { + fprintf(stderr, "Can't find symbol %s", sym); + return (false); + } + if (!read_at_address(addr, buf, len)) { + fprintf(stderr, "Can't read from kernel"); + return (false); + } + return (true); +} + +#ifndef _STANDALONE +/* + * Silly little test case to test on a random Linux system. + */ +int +main(int argc, char **argv) +{ + struct boot_params bp; + + if (data_from_kernel("boot_params", &bp, sizeof(bp))) { + fprintf(stderr, "Something went wrong\n"); + } else { + printf("sig %#x systab %#lx memmap %#lx mmapsize %d md_size %d md_vers %d\n", + bp.efi_info.efi_loader_signature, + (long)(bp.efi_info.efi_systab | ((long)bp.efi_info.efi_systab_hi << 32)), + (long)(bp.efi_info.efi_memmap | ((long)bp.efi_info.efi_memmap_hi << 32)), + bp.efi_info.efi_memmap_size, bp.efi_info.efi_memdesc_size, + bp.efi_info.efi_memdesc_version); + } +} +#endif diff --git a/stand/kboot/libkboot/efi.c b/stand/kboot/libkboot/efi.c index 1f7f28093819..3f1055f6d538 100644 --- a/stand/kboot/libkboot/efi.c +++ b/stand/kboot/libkboot/efi.c @@ -5,8 +5,156 @@ */ #include <sys/param.h> +#include <sys/linker.h> #include "stand.h" +#include "bootstrap.h" #include "efi.h" +#include "seg.h" +#include "util.h" + +vm_paddr_t efi_systbl_phys; +struct efi_map_header *efi_map_hdr; +uint32_t efi_map_size; +vm_paddr_t efi_map_phys_src; /* From DTB */ +vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */ + +void +efi_set_systbl(uint64_t tbl) +{ + efi_systbl_phys = tbl; +} + +#if 0 +/* Note: This is useless since runtime-map is a subset */ +void +efi_read_from_sysfs(void) +{ + uint32_t efisz, sz, map_size; + int entries = 0; + struct efi_md *map; /* Really an array */ + char *buf; + struct stat sb; + char fn[100]; + + /* + * Count the number of entries we have. They are numbered from 0 + * through entries - 1. + */ + do { + printf("Looking at index %d\n", entries); + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", entries++); + } while (stat(fn, &sb) == 0); + + /* + * We incremented entries one past the first failure, so we need to + * adjust the count and the test for 'nothing found' is against 1. + */ + if (entries == 1) + goto err; + entries--; + + /* XXX lots of copied code, refactor? */ + map_size = sizeof(struct efi_md) * entries; + efisz = roundup2(sizeof(*efi_map_hdr), 16); + sz = efisz + map_size; + buf = malloc(efisz + map_size); + if (buf == NULL) + return; + efi_map_hdr = (struct efi_map_header *)buf; + efi_map_size = sz; + map = (struct efi_md *)(buf + efisz); + bzero(map, sz); + efi_map_hdr->memory_size = map_size; + efi_map_hdr->descriptor_size = sizeof(struct efi_md); + efi_map_hdr->descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; + for (int i = 0; i < entries; i++) { + struct efi_md *m; + + printf("Populating index %d\n", i); + m = map + i; + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/type", i); + if (!file2u32(fn, &m->md_type)) + goto err; + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", i); + if (!file2u64(fn, &m->md_phys)) + goto err; + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/virt_addr", i); + if (!file2u64(fn, &m->md_virt)) + goto err; + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/num_pages", i); + if (!file2u64(fn, &m->md_pages)) + goto err; + snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/attribute", i); + if (!file2u64(fn, &m->md_attr)) + goto err; + } + efi_map_phys_src = 0; + printf("UEFI MAP:\n"); + print_efi_map(efi_map_hdr); + printf("DONE\n"); + return; +err: + printf("Parse error in reading current memory map\n"); +} +#endif + +/* + * We may have no ability to read the PA that this map is in, so pass + * the address to FreeBSD via a rather odd flag entry as the first map + * so early boot can copy the memory map into this space and have the + * rest of the code cope. + */ +bool +efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers) +{ + uint32_t efisz, sz; + char *buf; + int fd2, len; + struct efi_md *map; /* Really an array */ + + /* + * We may have no ability to read the PA that this map is in, so pass + * the address to FreeBSD via a rather odd flag entry as the first map + * so early boot can copy the memory map into this space and have the + * rest of the code cope. We also have to round the size of the header + * to 16 byte boundary. + */ + efisz = roundup2(sizeof(*efi_map_hdr), 16); + sz = efisz + map_size; + buf = malloc(efisz + map_size); + if (buf == NULL) + return false; + efi_map_hdr = (struct efi_map_header *)buf; + efi_map_size = sz; + map = (struct efi_md *)(buf + efisz); + bzero(map, sz); + efi_map_hdr->memory_size = map_size; + efi_map_hdr->descriptor_size = desc_size; + efi_map_hdr->descriptor_version = vers; + + /* + * Try to read in the actual UEFI map. This may fail, and that's OK. We just + * won't print the map. + */ + fd2 = open("host:/dev/mem", O_RDONLY); + if (fd2 < 0) + goto no_read; + if (lseek(fd2, pa, SEEK_SET) < 0) + goto no_read; + len = read(fd2, map, sz); + if (len != sz) + goto no_read; + efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */ + close(fd2); + printf("UEFI MAP:\n"); + print_efi_map(efi_map_hdr); + return (true); + +no_read: /* Just get it the trampoline */ + efi_map_phys_src = pa; + close(fd2); + return (true); +} void foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp) @@ -32,6 +180,7 @@ foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void * } } +/* XXX REFACTOR WITH KERNEL */ static void print_efi_map_entry(struct efi_md *p, void *argp __unused) { @@ -95,3 +244,26 @@ print_efi_map(struct efi_map_header *efihdr) foreach_efi_map_entry(efihdr, print_efi_map_entry, NULL); } + +void +efi_bi_loadsmap(struct preloaded_file *kfp) +{ + /* + * Make a note of a systbl. This is nearly mandatory on AARCH64. + */ + if (efi_systbl_phys) + file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys); + + /* + * If we have efi_map_hdr, then it's a pointer to the PA where this + * memory map lives. The trampoline code will copy it over. If we don't + * have it, panic because /proc/iomem isn't sufficient and there's no + * hope. + */ + if (efi_map_hdr != NULL) { + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr); + return; + } + + panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n"); +} diff --git a/stand/kboot/libkboot/seg.c b/stand/kboot/libkboot/seg.c index 6979d5cfa5fd..708170b6c381 100644 --- a/stand/kboot/libkboot/seg.c +++ b/stand/kboot/libkboot/seg.c @@ -216,8 +216,7 @@ static struct kv { linux_code, "Kernel code", KV_KEEPER }, { linux_data, "Kernel data", KV_KEEPER }, { linux_bss, "Kernel bss", KV_KEEPER }, - { firmware_reserved, "reserved" }, - { 0, NULL }, + { firmware_reserved, "Reserved" }, }; static const char * diff --git a/stand/kboot/libkboot/util.c b/stand/kboot/libkboot/util.c index 0100a7cc5d8a..c7fe8b542643 100644 --- a/stand/kboot/libkboot/util.c +++ b/stand/kboot/libkboot/util.c @@ -44,3 +44,16 @@ file2u64(const char *fn, uint64_t *val) *val = v; return true; } + +bool +file2u32(const char *fn, uint32_t *val) +{ + unsigned long v; + char buffer[80]; + + if (!file2str(fn, buffer, sizeof(buffer))) + return false; + v = strtoul(buffer, NULL, 0); /* XXX check return values? */ + *val = v; + return true; +} diff --git a/stand/kshim/bsd_kernel.c b/stand/kshim/bsd_kernel.c index 91ca46e18d74..455ae570d8ae 100644 --- a/stand/kshim/bsd_kernel.c +++ b/stand/kshim/bsd_kernel.c @@ -1326,12 +1326,13 @@ usb_pci_mod_load(void *arg) { uint32_t x; - usb_pci_root = device_add_child(NULL, "pci", -1); + usb_pci_root = device_add_child(NULL, "pci", DEVICE_UNIT_ANY); if (usb_pci_root == NULL) return; for (x = 0; x != USB_PCI_USB_MAX; x++) { - usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); + usb_pci_dev[x] = device_add_child(usb_pci_root, + usb_pci_devices[x], DEVICE_UNIT_ANY); if (usb_pci_dev[x] == NULL) continue; if (device_probe_and_attach(usb_pci_dev[x])) { diff --git a/stand/liblua/Makefile b/stand/liblua/Makefile index ce7eb89fe494..b1c34ec0a466 100644 --- a/stand/liblua/Makefile +++ b/stand/liblua/Makefile @@ -24,7 +24,7 @@ SRCS+= lauxlib.c lbaselib.c lstrlib.c loadlib.c SRCS+= lerrno.c lpager.c lstd.c lutils.c SRCS+= gfx_utils.c -.PATH: ${FLUASRC}/modules +.PATH: ${FLUASRC}/lfs SRCS+= lfs.c .PATH: ${FLUALIB}/libhash SRCS+= lhash.c diff --git a/stand/liblua/lstd.h b/stand/liblua/lstd.h index ce3aef4bc5fc..2b601f129566 100644 --- a/stand/liblua/lstd.h +++ b/stand/liblua/lstd.h @@ -29,10 +29,10 @@ #include <stand.h> #include <sys/types.h> +#include <sys/stdarg.h> #include <sys/stdint.h> #include <limits.h> #include <string.h> -#include <machine/stdarg.h> /* * Mini stdio FILE and DIR routines. These are the minimal routines needed by diff --git a/stand/libofw/ofw_disk.c b/stand/libofw/ofw_disk.c index fc4c25bd9424..d4bce64d9be5 100644 --- a/stand/libofw/ofw_disk.c +++ b/stand/libofw/ofw_disk.c @@ -28,11 +28,10 @@ */ #include <sys/param.h> +#include <sys/stdarg.h> #include <netinet/in.h> -#include <machine/stdarg.h> - #include <stand.h> #include <sys/disk.h> diff --git a/stand/libofw/openfirm.c b/stand/libofw/openfirm.c index 58e7d8cbe755..1df65784e47a 100644 --- a/stand/libofw/openfirm.c +++ b/stand/libofw/openfirm.c @@ -56,8 +56,7 @@ */ #include <sys/endian.h> - -#include <machine/stdarg.h> +#include <sys/stdarg.h> #include <stand.h> diff --git a/stand/libsa/Makefile b/stand/libsa/Makefile index 42ef3e69c18a..f5a1acea843e 100644 --- a/stand/libsa/Makefile +++ b/stand/libsa/Makefile @@ -209,8 +209,8 @@ beforedepend: for i in ${SAFE_INCS}; do \ ln -sf ${SRCTOP}/include/$$i $$i; \ done; \ - ln -sf ${SYSDIR}/${MACHINE}/include/stdarg.h stdarg.h; \ ln -sf ${SYSDIR}/sys/errno.h errno.h; \ + ln -sf ${SYSDIR}/sys/stdarg.h stdarg.h; \ ln -sf ${SYSDIR}/sys/stdint.h stdint.h; \ ln -sf ${SRCTOP}/include/arpa/inet.h arpa/inet.h; \ ln -sf ${SRCTOP}/include/arpa/tftp.h arpa/tftp.h; \ diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c index d919bb59e843..ac37553c6d34 100644 --- a/stand/libsa/bootp.c +++ b/stand/libsa/bootp.c @@ -42,7 +42,6 @@ #include <string.h> -#define BOOTP_DEBUGxx #define SUPPORT_DHCP #define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ @@ -130,10 +129,7 @@ bootp(int sock) } wbuf; struct bootp *rbootp; -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp: socket=%d\n", sock); -#endif + DEBUG_PRINTF(1, ("bootp: socket=%d\n", sock)); if (!bot) bot = getsecs(); @@ -141,10 +137,7 @@ bootp(int sock) printf("bootp: bad socket. %d\n", sock); return; } -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp: d=%lx\n", (long)d); -#endif + DEBUG_PRINTF(1, ("bootp: socktodesc=%lx\n", (long)d)); bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); @@ -225,31 +218,20 @@ bootp(int sock) netmask = htonl(IN_CLASSB_NET); else netmask = htonl(IN_CLASSC_NET); -#ifdef BOOTP_DEBUG - if (debug) - printf("'native netmask' is %s\n", intoa(netmask)); -#endif + DEBUG_PRINTF(1, ("'native netmask' is %s\n", intoa(netmask))); } -#ifdef BOOTP_DEBUG - if (debug) - printf("mask: %s\n", intoa(netmask)); -#endif + DEBUG_PRINTF(1,("rootip: %s\n", inet_ntoa(rootip))); + DEBUG_PRINTF(1,("mask: %s\n", intoa(netmask))); /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { -#ifdef BOOTP_DEBUG - if (debug) - printf("need gateway for root ip\n"); -#endif + DEBUG_PRINTF(1,("need gateway for root ip\n")); } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { -#ifdef BOOTP_DEBUG - if (debug) - printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); -#endif + DEBUG_PRINTF(1,("gateway ip (%s) bad\n", inet_ntoa(gateip))); gateip.s_addr = 0; } @@ -264,18 +246,11 @@ bootpsend(struct iodesc *d, void *pkt, size_t len) { struct bootp *bp; -#ifdef BOOTP_DEBUG - if (debug) - printf("bootpsend: d=%lx called.\n", (long)d); -#endif - + DEBUG_PRINTF(1,("bootpsend: d=%lx called.\n", (long)d)); bp = pkt; bp->bp_secs = htons((u_short)(getsecs() - bot)); -#ifdef BOOTP_DEBUG - if (debug) - printf("bootpsend: calling sendudp\n"); -#endif + DEBUG_PRINTF(1,("bootpsend: calling sendudp\n")); return (sendudp(d, pkt, len)); } @@ -288,34 +263,22 @@ bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, struct bootp *bp; void *ptr; -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp_recvoffer: called\n"); -#endif + DEBUG_PRINTF(1,("bootp_recvoffer: called\n")); ptr = NULL; n = readudp(d, &ptr, (void **)&bp, tleft); if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) goto bad; -#ifdef BOOTP_DEBUG - if (debug) - printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n); -#endif + DEBUG_PRINTF(1,("bootprecv: checked. bp = %p, n = %zd\n", bp, n)); + if (bp->bp_xid != htonl(d->xid)) { -#ifdef BOOTP_DEBUG - if (debug) { - printf("bootprecv: expected xid 0x%lx, got 0x%x\n", - d->xid, ntohl(bp->bp_xid)); - } -#endif + DEBUG_PRINTF(1,("bootprecv: expected xid 0x%lx, got 0x%x\n", + d->xid, ntohl(bp->bp_xid))); goto bad; } -#ifdef BOOTP_DEBUG - if (debug) - printf("bootprecv: got one!\n"); -#endif + DEBUG_PRINTF(1,("bootprecv: got one!\n")); /* Suck out vendor info */ if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { @@ -359,10 +322,7 @@ vend_rfc1048(u_char *cp, u_int len) u_char tag; const char *val; -#ifdef BOOTP_DEBUG - if (debug) - printf("vend_rfc1048 bootp info. len=%d\n", len); -#endif + DEBUG_PRINTF(1,("vend_rfc1048 bootp info. len=%d\n", len)); ep = cp + len; /* Step over magic cookie */ @@ -443,10 +403,8 @@ vend_cmu(u_char *cp) { struct cmu_vend *vp; -#ifdef BOOTP_DEBUG - if (debug) - printf("vend_cmu bootp info.\n"); -#endif + DEBUG_PRINTF(1,("vend_cmu bootp info.\n")); + vp = (struct cmu_vend *)cp; if (vp->v_smask.s_addr != 0) { diff --git a/stand/libsa/bzipfs.c b/stand/libsa/bzipfs.c index f4002796f0ae..ff7ec16e7dc6 100644 --- a/stand/libsa/bzipfs.c +++ b/stand/libsa/bzipfs.c @@ -68,6 +68,7 @@ static int bzf_stat(struct open_file *f, struct stat *sb); #ifndef REGRESSION struct fs_ops bzipfs_fsops = { .fs_name = "bzip", + .fs_flags = 0, .fo_open = bzf_open, .fo_close = bzf_close, .fo_read = bzf_read, diff --git a/stand/libsa/cd9660.c b/stand/libsa/cd9660.c index 973a7dddcda9..d1da39aa479a 100644 --- a/stand/libsa/cd9660.c +++ b/stand/libsa/cd9660.c @@ -81,6 +81,7 @@ static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, struct fs_ops cd9660_fsops = { .fs_name = "cd9660", + .fs_flags = 0, .fo_open = cd9660_open, .fo_close = cd9660_close, .fo_read = cd9660_read, diff --git a/stand/libsa/dosfs.c b/stand/libsa/dosfs.c index aca198cdf6fa..38610d917007 100644 --- a/stand/libsa/dosfs.c +++ b/stand/libsa/dosfs.c @@ -61,6 +61,7 @@ static int dos_unmount(const char *dev, void *data); struct fs_ops dosfs_fsops = { .fs_name = "dosfs", + .fs_flags = 0, .fo_open = dos_open, .fo_close = dos_close, .fo_read = dos_read, diff --git a/stand/libsa/environment.c b/stand/libsa/environment.c index 95ee1718f8d4..d139249a8e84 100644 --- a/stand/libsa/environment.c +++ b/stand/libsa/environment.c @@ -66,6 +66,17 @@ env_setenv(const char *name, int flags, const void *value, if ((ev = env_getenv(name)) != NULL) { /* + * If the new value doesn't have NOKENV set, we'll drop the flag + * if it's set on the entry so that the override propagates + * correctly. We do this *before* sending it to the hook in + * case the hook declines to operate on it (e.g., because the + * value matches what was already set) -- we would still want + * the explicitly set value to propagate. + */ + if (!(flags & EV_NOKENV)) + ev->ev_flags &= ~EV_NOKENV; + + /* * If there's a set hook, let it do the work * (unless we are working for one already). */ @@ -77,7 +88,6 @@ env_setenv(const char *name, int flags, const void *value, free(ev->ev_value); ev->ev_value = NULL; ev->ev_flags &= ~EV_DYNAMIC; - } else { /* @@ -123,12 +133,13 @@ env_setenv(const char *name, int flags, const void *value, /* If we have a new value, use it */ if (flags & EV_VOLATILE) { ev->ev_value = strdup(value); - ev->ev_flags |= EV_DYNAMIC; + flags |= EV_DYNAMIC; } else { ev->ev_value = (char *)value; - ev->ev_flags |= flags & EV_DYNAMIC; } + ev->ev_flags |= flags & (EV_DYNAMIC | EV_NOKENV); + return (0); } diff --git a/stand/libsa/ext2fs.c b/stand/libsa/ext2fs.c index 47812f4543a1..f7096282f156 100644 --- a/stand/libsa/ext2fs.c +++ b/stand/libsa/ext2fs.c @@ -106,6 +106,7 @@ static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, struct fs_ops ext2fs_fsops = { .fs_name = "ext2fs", + .fs_flags = 0, .fo_open = ext2fs_open, .fo_close = ext2fs_close, .fo_read = ext2fs_read, diff --git a/stand/libsa/globals.c b/stand/libsa/globals.c index 2797045d4faf..6bd3a4243d73 100644 --- a/stand/libsa/globals.c +++ b/stand/libsa/globals.c @@ -17,6 +17,7 @@ u_char bcea[6] = BA; /* broadcast ethernet address */ char rootpath[FNAME_SIZE] = "/"; /* root mount path */ +int rootport; /* port for rootpath server */ char bootfile[FNAME_SIZE]; /* bootp says to boot this */ char hostname[FNAME_SIZE]; /* our hostname */ int hostnamelen; diff --git a/stand/libsa/gzipfs.c b/stand/libsa/gzipfs.c index 6c2b8cac9e34..6b22f750f3ef 100644 --- a/stand/libsa/gzipfs.c +++ b/stand/libsa/gzipfs.c @@ -50,6 +50,7 @@ static int zf_stat(struct open_file *f, struct stat *sb); struct fs_ops gzipfs_fsops = { .fs_name = "zip", + .fs_flags = 0, .fo_open = zf_open, .fo_close = zf_close, .fo_read = zf_read, diff --git a/stand/libsa/hexdump.c b/stand/libsa/hexdump.c index 83fd5e277f1b..cce6e323c2cb 100644 --- a/stand/libsa/hexdump.c +++ b/stand/libsa/hexdump.c @@ -61,7 +61,7 @@ hexdump(caddr_t region, size_t len) for (x = 0; x < 16; x++) { if ((line + x) < (region + len)) { c = *(uint8_t *)(line + x); - if ((c < ' ') || (c > '~')) /* !isprint(c) */ + if (!isprint(c)) c = '.'; emit("%c", c); } else { diff --git a/stand/libsa/ip.c b/stand/libsa/ip.c index 2c2acf2eda16..e9e4f519681d 100644 --- a/stand/libsa/ip.c +++ b/stand/libsa/ip.c @@ -42,6 +42,7 @@ #include <sys/queue.h> #include <string.h> +#include <stdbool.h> #include <net/if.h> #include <netinet/in.h> @@ -89,17 +90,10 @@ sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) struct ip *ip; u_char *ea; -#ifdef NET_DEBUG - if (debug) { - printf("sendip: proto: %x d=%p called.\n", proto, (void *)d); - if (d) { - printf("saddr: %s:%d", - inet_ntoa(d->myip), ntohs(d->myport)); - printf(" daddr: %s:%d\n", - inet_ntoa(d->destip), ntohs(d->destport)); - } - } -#endif + DEBUG_PRINTF(1, ("sendip: proto: %x d=%p called.\n", proto, (void *)d)); + DEBUG_PRINTF(1, ("saddr: %s:%d daddr: %s:%d\n", + inet_ntoa(d->myip), ntohs(d->myport), + inet_ntoa(d->destip), ntohs(d->destport))); ip = (struct ip *)pkt - 1; len += sizeof(*ip); @@ -143,137 +137,123 @@ ip_reasm_free(struct ip_reasm *ipr) free(ipr); } -static int +static bool ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) { - struct ip_queue *ipq, *prev, *p; + struct ip_queue *ipq, *p; + uint16_t off_q, off_ip; - if ((ipq = calloc(1, sizeof (*ipq))) == NULL) - return (1); + if ((ipq = calloc(1, sizeof(*ipq))) == NULL) + return (false); ipq->ipq_pkt = pkt; ipq->ipq_hdr = ip; - prev = NULL; STAILQ_FOREACH(p, &ipr->ip_queue, ipq_next) { - if ((ntohs(p->ipq_hdr->ip_off) & IP_OFFMASK) < - (ntohs(ip->ip_off) & IP_OFFMASK)) { - prev = p; - continue; + off_q = ntohs(p->ipq_hdr->ip_off) & IP_OFFMASK; + off_ip = ntohs(ip->ip_off) & IP_OFFMASK; + + if (off_q == off_ip) { /* duplicate */ + free(pkt); + free(ipq); + return (true); } - if (prev == NULL) + + if (off_ip < off_q) { + /* + * Everything in queue has larger offset, + * drop out of loop and insert to HEAD. + */ break; + } + + /* + * p in queue is smaller than ip, check if we need to put + * ip after p or after p->next. + */ + struct ip_queue *next = STAILQ_NEXT(p, ipq_next); + if (next == NULL) { + /* insert after p */ + STAILQ_INSERT_AFTER(&ipr->ip_queue, p, ipq, ipq_next); + return (true); + } - STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); - return (0); + off_q = ntohs(next->ipq_hdr->ip_off) & IP_OFFMASK; + if (off_ip < off_q) { + /* next fragment offset is larger, insert after p. */ + STAILQ_INSERT_AFTER(&ipr->ip_queue, p, ipq, ipq_next); + return (true); + } + /* next fragment offset is smaller, loop */ } STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); - return (0); + return (true); } /* * Receive a IP packet and validate it is for us. */ static ssize_t -readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, - uint8_t proto) +readipv4(struct iodesc *d, void **pkt, void **payload, ssize_t n) { - ssize_t n; + struct ip *ip = *payload; size_t hlen; struct ether_header *eh; - struct ip *ip; struct udphdr *uh; - uint16_t etype; /* host order */ - char *ptr; + char *ptr = *pkt; struct ip_reasm *ipr; struct ip_queue *ipq, *last; + bool morefrag, isfrag; + uint16_t fragoffset; -#ifdef NET_DEBUG - if (debug) - printf("readip: called\n"); -#endif - - ip = NULL; - ptr = NULL; - n = readether(d, (void **)&ptr, (void **)&ip, tleft, &etype); - if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { - free(ptr); - return (-1); - } - - /* Ethernet address checks now in readether() */ - - /* Need to respond to ARP requests. */ - if (etype == ETHERTYPE_ARP) { - struct arphdr *ah = (void *)ip; - if (ah->ar_op == htons(ARPOP_REQUEST)) { - /* Send ARP reply */ - arp_reply(d, ah); - } + if (n < sizeof(*ip)) { free(ptr); errno = EAGAIN; /* Call me again. */ return (-1); } - if (etype != ETHERTYPE_IP) { -#ifdef NET_DEBUG - if (debug) - printf("readip: not IP. ether_type=%x\n", etype); -#endif - free(ptr); - return (-1); - } - - /* Check ip header */ - if (ip->ip_v != IPVERSION || /* half char */ - ip->ip_p != proto) { -#ifdef NET_DEBUG - if (debug) { - printf("readip: IP version or proto. ip_v=%d ip_p=%d\n", - ip->ip_v, ip->ip_p); - } -#endif - free(ptr); - return (-1); - } - hlen = ip->ip_hl << 2; if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) { -#ifdef NET_DEBUG - if (debug) - printf("readip: short hdr or bad cksum.\n"); -#endif + DEBUG_PRINTF(1, ("%s: short hdr or bad cksum.\n", __func__)); free(ptr); + errno = EAGAIN; /* Call me again. */ return (-1); } + if (n < ntohs(ip->ip_len)) { -#ifdef NET_DEBUG - if (debug) - printf("readip: bad length %d < %d.\n", - (int)n, ntohs(ip->ip_len)); -#endif + DEBUG_PRINTF(1, ("readip: bad length %zd < %d.\n", + n, ntohs(ip->ip_len))); free(ptr); + errno = EAGAIN; /* Call me again. */ return (-1); } + + fragoffset = (ntohs(ip->ip_off) & IP_OFFMASK) * 8; + morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? false : true; + isfrag = morefrag || fragoffset != 0; + + uh = (struct udphdr *)((uintptr_t)ip + sizeof(*ip)); + if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { -#ifdef NET_DEBUG - if (debug) { - printf("readip: bad saddr %s != ", inet_ntoa(d->myip)); - printf("%s\n", inet_ntoa(ip->ip_dst)); - } -#endif + DEBUG_PRINTF(1, ("%s: not for us: saddr %s (%d) != %s (%d)\n", + __func__, inet_ntoa(d->myip), ntohs(d->myport), + inet_ntoa(ip->ip_dst), ntohs(uh->uh_dport))); free(ptr); + errno = EAGAIN; /* Call me again. */ return (-1); } /* Unfragmented packet. */ - if ((ntohs(ip->ip_off) & IP_MF) == 0 && - (ntohs(ip->ip_off) & IP_OFFMASK) == 0) { - uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); + if (!isfrag) { + DEBUG_PRINTF(1, ("%s: unfragmented saddr %s:%d -> %s:%d\n", + __func__, + inet_ntoa(ip->ip_src), ntohs(uh->uh_sport), + inet_ntoa(ip->ip_dst), ntohs(uh->uh_dport))); /* If there were ip options, make them go away */ if (hlen != sizeof(*ip)) { - bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); + bcopy(((u_char *)ip) + hlen, uh, + ntohs(uh->uh_ulen) - hlen); ip->ip_len = htons(sizeof(*ip)); n -= hlen - sizeof(*ip); } @@ -295,7 +275,7 @@ readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, /* Allocate new reassembly entry */ if (ipr == NULL) { - if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { + if ((ipr = calloc(1, sizeof(*ipr))) == NULL) { free(ptr); return (-1); } @@ -307,37 +287,22 @@ readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, ipr->ip_ttl = MAXTTL; STAILQ_INIT(&ipr->ip_queue); STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); + DEBUG_PRINTF(1, ("%s: new reassembly ID=%d %s -> %s\n", + __func__, ntohs(ip->ip_id), inet_ntoa(ip->ip_src), + inet_ntoa(ip->ip_dst))); } - if (ip_reasm_add(ipr, ptr, ip) != 0) { + /* + * NOTE: with ip_reasm_add() ptr will be stored in reassembly + * queue and we can not free it without destroying the queue. + */ + if (!ip_reasm_add(ipr, ptr, ip)) { STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); free(ipr); free(ptr); return (-1); } - if ((ntohs(ip->ip_off) & IP_MF) == 0) { - ipr->ip_total_size = (8 * (ntohs(ip->ip_off) & IP_OFFMASK)); - ipr->ip_total_size += n + sizeof (*ip); - ipr->ip_total_size += sizeof (struct ether_header); - - ipr->ip_pkt = malloc(ipr->ip_total_size + 2); - if (ipr->ip_pkt == NULL) { - STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); - ip_reasm_free(ipr); - return (-1); - } - } - - /* - * If we do not have re-assembly buffer ipr->ip_pkt, we are still - * missing fragments, so just restart the read. - */ - if (ipr->ip_pkt == NULL) { - errno = EAGAIN; - return (-1); - } - /* * Walk the packet list in reassembly queue, if we got all the * fragments, build the packet. @@ -345,35 +310,59 @@ readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, n = 0; last = NULL; STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { - if ((ntohs(ipq->ipq_hdr->ip_off) & IP_OFFMASK) != n / 8) { - STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); - ip_reasm_free(ipr); + fragoffset = (ntohs(ipq->ipq_hdr->ip_off) & IP_OFFMASK) * 8; + if (fragoffset != n) { + DEBUG_PRINTF(1, ("%s: need more fragments %d %s -> ", + __func__, ntohs(ipq->ipq_hdr->ip_id), + inet_ntoa(ipq->ipq_hdr->ip_src))); + DEBUG_PRINTF(1, ("%s offset=%d MF=%d\n", + inet_ntoa(ipq->ipq_hdr->ip_dst), + fragoffset, + (ntohs(ipq->ipq_hdr->ip_off) & IP_MF) != 0)); + errno = EAGAIN; return (-1); } n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); last = ipq; } + + /* complete queue has last packet with MF 0 */ if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { + DEBUG_PRINTF(1, ("%s: need more fragments %d %s -> ", + __func__, ntohs(last->ipq_hdr->ip_id), + inet_ntoa(last->ipq_hdr->ip_src))); + DEBUG_PRINTF(1, ("%s offset=%d MF=%d\n", + inet_ntoa(last->ipq_hdr->ip_dst), + (ntohs(last->ipq_hdr->ip_off) & IP_OFFMASK) * 8, + (ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0)); errno = EAGAIN; return (-1); } + ipr->ip_total_size = n + sizeof(*ip) + sizeof(struct ether_header); + ipr->ip_pkt = malloc(ipr->ip_total_size + 2); + if (ipr->ip_pkt == NULL) { + STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); + ip_reasm_free(ipr); + return (-1); + } + ipq = STAILQ_FIRST(&ipr->ip_queue); /* Fabricate ethernet header */ eh = (struct ether_header *)((uintptr_t)ipr->ip_pkt + 2); - bcopy((void *)((uintptr_t)ipq->ipq_pkt + 2), eh, sizeof (*eh)); + bcopy((void *)((uintptr_t)ipq->ipq_pkt + 2), eh, sizeof(*eh)); /* Fabricate IP header */ - ipr->ip_hdr = (struct ip *)((uintptr_t)eh + sizeof (*eh)); - bcopy(ipq->ipq_hdr, ipr->ip_hdr, sizeof (*ipr->ip_hdr)); - ipr->ip_hdr->ip_hl = sizeof (*ipr->ip_hdr) >> 2; + ipr->ip_hdr = (struct ip *)((uintptr_t)eh + sizeof(*eh)); + bcopy(ipq->ipq_hdr, ipr->ip_hdr, sizeof(*ipr->ip_hdr)); + ipr->ip_hdr->ip_hl = sizeof(*ipr->ip_hdr) >> 2; ipr->ip_hdr->ip_len = htons(n); ipr->ip_hdr->ip_sum = 0; - ipr->ip_hdr->ip_sum = in_cksum(ipr->ip_hdr, sizeof (*ipr->ip_hdr)); + ipr->ip_hdr->ip_sum = in_cksum(ipr->ip_hdr, sizeof(*ipr->ip_hdr)); n = 0; - ptr = (char *)((uintptr_t)ipr->ip_hdr + sizeof (*ipr->ip_hdr)); + ptr = (char *)((uintptr_t)ipr->ip_hdr + sizeof(*ipr->ip_hdr)); STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { char *data; size_t len; @@ -395,6 +384,9 @@ readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, STAILQ_REMOVE_HEAD(&ire_list, ip_next); ip_reasm_free(ipr); } + DEBUG_PRINTF(1, ("%s: completed fragments ID=%d %s -> %s\n", + __func__, ntohs(ip->ip_id), inet_ntoa(ip->ip_src), + inet_ntoa(ip->ip_dst))); return (n); } @@ -410,15 +402,63 @@ readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, t = getsecs(); while ((getsecs() - t) < tleft) { + ssize_t n; + uint16_t etype; /* host order */ + void *ptr = NULL; + void *data = NULL; + errno = 0; - ret = readipv4(d, pkt, payload, tleft, proto); - if (ret >= 0) - return (ret); - /* Bubble up the error if it wasn't successful */ - if (errno != EAGAIN) - return (-1); + n = readether(d, &ptr, &data, tleft, &etype); + if (n == -1) { + free(ptr); + continue; + } + /* Ethernet address checks are done in readether() */ + + /* Need to respond to ARP requests. */ + if (etype == ETHERTYPE_ARP) { + struct arphdr *ah = data; + + DEBUG_PRINTF(1, ("%s: ARP request\n", __func__)); + + if (ah->ar_op == htons(ARPOP_REQUEST)) { + /* Send ARP reply */ + arp_reply(d, ah); + } + free(ptr); + continue; /* Get next packet */ + } + + if (etype == ETHERTYPE_IP) { + struct ip *ip = data; + + if (ip->ip_v == IPVERSION && /* half char */ + ip->ip_p == proto) { + errno = 0; + ret = readipv4(d, &ptr, &data, n); + if (ret >= 0) { + *pkt = ptr; + *payload = data; + return (ret); + } + + /* + * Bubble up the error if it wasn't successful + */ + if (errno != EAGAIN) + return (-1); + continue; + } + DEBUG_PRINTF(1, ("%s: IP version or proto. " + "ip_v=%d ip_p=%d\n", + __func__, ip->ip_v, ip->ip_p)); + free(ptr); + continue; + } + free(ptr); } /* We've exhausted tleft; timeout */ errno = ETIMEDOUT; + DEBUG_PRINTF(1, ("%s: timeout\n", __func__)); return (-1); } diff --git a/stand/libsa/libsa.3 b/stand/libsa/libsa.3 index 3e3f70610516..0947f97a0a1f 100644 --- a/stand/libsa/libsa.3 +++ b/stand/libsa/libsa.3 @@ -781,6 +781,10 @@ The same as but for .Xr bzip2 1 Ns -compressed files. +.It Va pkgfs_fsops +File access from a tar file typically streamed via TFTP. +The order of files in the tar file must match the order they are +to be consumed as rewind is not practical. .El .Pp The array of diff --git a/stand/libsa/mount.c b/stand/libsa/mount.c index 73bf6ab8118c..c866dc9c7055 100644 --- a/stand/libsa/mount.c +++ b/stand/libsa/mount.c @@ -107,7 +107,10 @@ mount(const char *dev, const char *path, int flags __unused, void *data) fs = file_system[i]; if (fs->fo_mount == NULL) continue; - + DEBUG_PRINTF(1,("%s: fs=%s path=%s\n", + __func__, fs->fs_name, path)); + if (is_tftp()) + break; if (fs->fo_mount(dev, path, &data) != 0) continue; diff --git a/stand/libsa/net.h b/stand/libsa/net.h index d4823d88f58b..945b6b9ea45f 100644 --- a/stand/libsa/net.h +++ b/stand/libsa/net.h @@ -75,6 +75,7 @@ enum net_proto { extern u_char bcea[6]; extern char rootpath[FNAME_SIZE]; +extern int rootport; extern char bootfile[FNAME_SIZE]; extern char hostname[FNAME_SIZE]; extern int hostnamelen; diff --git a/stand/libsa/nfs.c b/stand/libsa/nfs.c index ee6af8a726c7..f3e9060c9881 100644 --- a/stand/libsa/nfs.c +++ b/stand/libsa/nfs.c @@ -131,6 +131,7 @@ struct nfs_iodesc nfs_root_node; struct fs_ops nfs_fsops = { .fs_name = "nfs", + .fs_flags = 0, .fo_open = nfs_open, .fo_close = nfs_close, .fo_read = nfs_read, diff --git a/stand/libsa/open.c b/stand/libsa/open.c index ccee4aa5c07b..91848aca7dbe 100644 --- a/stand/libsa/open.c +++ b/stand/libsa/open.c @@ -138,6 +138,8 @@ open(const char *fname, int mode) struct fs_ops *fs; struct open_file *f; int fd, i, error, besterror; + bool is_dir; + size_t n; const char *file; TSENTER(); @@ -154,31 +156,42 @@ open(const char *fname, int mode) f->f_devdata = NULL; file = NULL; + if (exclusive_file_system == NULL || + (exclusive_file_system->fs_flags & FS_OPS_NO_DEVOPEN) == 0) { + error = devopen(f, fname, &file); + if (error || + (((f->f_flags & F_NODEV) == 0) && f->f_dev == NULL)) + goto err; + + /* see if we opened a raw device; otherwise, 'file' is the file name. */ + if (file == NULL || *file == '\0') { + f->f_flags |= F_RAW; + f->f_rabuf = NULL; + TSEXIT(); + return (fd); + } + } else + file = fname; + if (exclusive_file_system != NULL) { + /* loader is forcing the filesystem to be used */ fs = exclusive_file_system; - error = (fs->fo_open)(fname, f); + error = (fs->fo_open)(file, f); if (error == 0) goto ok; goto err; } - error = devopen(f, fname, &file); - if (error || - (((f->f_flags & F_NODEV) == 0) && f->f_dev == NULL)) - goto err; - - /* see if we opened a raw device; otherwise, 'file' is the file name. */ - if (file == NULL || *file == '\0') { - f->f_flags |= F_RAW; - f->f_rabuf = NULL; - TSEXIT(); - return (fd); - } - /* pass file name to the different filesystem open routines */ besterror = ENOENT; + n = strlen(file); + is_dir = (n > 0 && file[n - 1] == '/'); for (i = 0; file_system[i] != NULL; i++) { fs = file_system[i]; + if (is_dir && is_tftp()) { + error = EOPNOTSUPP; + goto err; + } error = (fs->fo_open)(file, f); if (error == 0) goto ok; diff --git a/stand/libsa/panic.c b/stand/libsa/panic.c index 319f08094d92..a555743f0414 100644 --- a/stand/libsa/panic.c +++ b/stand/libsa/panic.c @@ -34,7 +34,7 @@ */ #include <stand.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> /* * Boot loaders and other standalone programs that wish to have a diff --git a/stand/libsa/pkgfs.c b/stand/libsa/pkgfs.c index 64ebdf033f14..6eb3badf7068 100644 --- a/stand/libsa/pkgfs.c +++ b/stand/libsa/pkgfs.c @@ -31,12 +31,6 @@ #include <string.h> #include <zlib.h> -#ifdef PKGFS_DEBUG -#define DBG(x) printf x -#else -#define DBG(x) -#endif - static int pkg_open(const char *, struct open_file *); static int pkg_close(struct open_file *); static int pkg_read(struct open_file *, void *, size_t, size_t *); @@ -47,6 +41,7 @@ static off_t pkg_atol(const char *, unsigned); struct fs_ops pkgfs_fsops = { .fs_name = "pkg", + .fs_flags = FS_OPS_NO_DEVOPEN, .fo_open = pkg_open, .fo_close = pkg_close, .fo_read = pkg_read, @@ -172,6 +167,9 @@ pkgfs_init(const char *pkgname, struct fs_ops *proto) exclusive_file_system = NULL; + DEBUG_PRINTF(0, ("%s(%s: '%s') -> %d (error=%d)\n", __func__, + proto->fs_name, pkgname, fd, errno)); + if (fd == -1) return (errno); @@ -239,7 +237,7 @@ pkg_open_follow(const char *fn, struct open_file *f, int lnks) if (strcmp(fn, tf->tf_hdr.ut_name) == 0) { f->f_fsdata = tf; tf->tf_fp = 0; /* Reset the file pointer. */ - DBG(("%s: found %s type %c\n", __func__, + DEBUG_PRINTF(1, ("%s: found %s type %c\n", __func__, fn, tf->tf_hdr.ut_typeflag[0])); if (tf->tf_hdr.ut_typeflag[0] == '2') { /* we have a symlink @@ -275,6 +273,7 @@ pkg_close(struct open_file *f) /* * Free up the cache if we read all of the file. */ + DEBUG_PRINTF(1, ("%s(%s)\n", __func__, tf->tf_hdr.ut_name)); if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) { free(tf->tf_cache); tf->tf_cachesz = 0; @@ -297,6 +296,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) return (EBADF); } + DEBUG_PRINTF(4, ("%s(%s,%zd)\n", __func__, tf->tf_hdr.ut_name, size)); + if (tf->tf_cachesz == 0) cache_data(tf, 1); @@ -334,6 +335,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) tf->tf_fp = fp; if (res != NULL) *res = size; + DEBUG_PRINTF(4, ("%s(%s) res=%zd\n", __func__, tf->tf_hdr.ut_name, + (ssize_t)(tf->tf_size - tf->tf_fp))); return ((sz == -1) ? errno : 0); } @@ -377,7 +380,7 @@ pkg_seek(struct open_file *f, off_t ofs, int whence) return (tf->tf_fp); } } - DBG(("%s: negative file seek (%jd)\n", __func__, + DEBUG_PRINTF(3, ("%s: negative file seek (%jd)\n", __func__, (intmax_t)delta)); errno = ESPIPE; return (-1); @@ -511,26 +514,28 @@ cache_data(struct tarfile *tf, int force) size_t sz; if (tf == NULL) { - DBG(("%s: no file to cache data for?\n", __func__)); + DEBUG_PRINTF(5, ("%s: no file to cache data for?\n", + __func__)); errno = EINVAL; return (-1); } pkg = tf->tf_pkg; if (pkg == NULL) { - DBG(("%s: no package associated with file?\n", __func__)); + DEBUG_PRINTF(5, ("%s: no package associated with file?\n", + __func__)); errno = EINVAL; return (-1); } if (tf->tf_cachesz > 0) { - DBG(("%s: data already cached\n", __func__)); + DEBUG_PRINTF(5, ("%s: data already cached\n", __func__)); errno = EINVAL; return (-1); } if (tf->tf_ofs != pkg->pkg_ofs) { - DBG(("%s: caching after force read of file %s?\n", + DEBUG_PRINTF(5, ("%s: caching after force read of file %s?\n", __func__, tf->tf_hdr.ut_name)); errno = EINVAL; return (-1); @@ -548,7 +553,8 @@ cache_data(struct tarfile *tf, int force) tf->tf_cache = malloc(sz); if (tf->tf_cache == NULL) { - DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz)); + DEBUG_PRINTF(5, ("%s: could not allocate %d bytes\n", + __func__, (int)sz)); errno = ENOMEM; return (-1); } @@ -732,7 +738,7 @@ new_package(int fd, struct package **pp) } /* - * Done parsing the ZIP header. Spkgt the inflation engine. + * Done parsing the ZIP header. Start the inflation engine. */ error = inflateInit2(&pkg->pkg_zs, -15); if (error != Z_OK) diff --git a/stand/libsa/printf.c b/stand/libsa/printf.c index a84c5431f536..053b54d31eff 100644 --- a/stand/libsa/printf.c +++ b/stand/libsa/printf.c @@ -37,18 +37,13 @@ */ #include <sys/types.h> +#include <sys/stdarg.h> #include <sys/stddef.h> #include <sys/stdint.h> #include <limits.h> #include <string.h> #include "stand.h" -/* - * Note that stdarg.h and the ANSI style va_start macro is used for both - * ANSI and traditional C compilers. - */ -#include <machine/stdarg.h> - #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) typedef void (kvprintf_fn_t)(int, void *); diff --git a/stand/libsa/smbios.c b/stand/libsa/smbios.c index 32cd198a9537..73b49a111f89 100644 --- a/stand/libsa/smbios.c +++ b/stand/libsa/smbios.c @@ -186,14 +186,17 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len) */ SMBIOS_GET8(cp, 0x0a) != 0 && smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { -#ifdef __ILP32__ +#if __SIZEOF_SIZE_T__ < 8 uint64_t end_addr; end_addr = SMBIOS_GET64(cp, 0x10) + /* Start address. */ SMBIOS_GET32(cp, 0x0c); /* Maximum size. */ - /* Is the table (or part of it) located above 4G? */ - if (end_addr >= (uint64_t)1 << 32) - /* Can't access it with 32-bit addressing. */ + /* + * Is the table (or part of it) located above what we + * can address? + */ + if ((size_t)end_addr != end_addr) + /* Yes, give it up. */ continue; #endif smbios.is_64bit_ep = 1; diff --git a/stand/libsa/splitfs.c b/stand/libsa/splitfs.c index 69912522000e..eb4b3a1feb11 100644 --- a/stand/libsa/splitfs.c +++ b/stand/libsa/splitfs.c @@ -50,6 +50,7 @@ static int splitfs_stat(struct open_file *f, struct stat *sb); struct fs_ops splitfs_fsops = { .fs_name = "split", + .fs_flags = 0, .fo_open = splitfs_open, .fo_close = splitfs_close, .fo_read = splitfs_read, diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h index e1188fb73a26..aaba0aa7fb39 100644 --- a/stand/libsa/stand.h +++ b/stand/libsa/stand.h @@ -94,6 +94,8 @@ __BEGIN_DECLS struct open_file; +#define FS_OPS_NO_DEVOPEN 1 + /* * This structure is used to define file system operations in a file system * independent way. @@ -104,6 +106,7 @@ struct open_file; */ struct fs_ops { const char *fs_name; + int fs_flags; int (*fo_open)(const char *path, struct open_file *f); int (*fo_close)(struct open_file *f); int (*fo_read)(struct open_file *f, void *buf, @@ -275,6 +278,11 @@ static __inline int ispunct(int c) (c >= '[' && c <= '`') || (c >= '{' && c <= '~'); } +static __inline int isprint(int c) +{ + return (c >= ' ') && (c <= '~'); +} + static __inline int toupper(int c) { return islower(c) ? c - 'a' + 'A' : c; @@ -344,6 +352,7 @@ extern int pager_file(const char *fname); #define EV_DYNAMIC (1<<0) /* value was dynamically allocated, free if changed/unset */ #define EV_VOLATILE (1<<1) /* value is volatile, make a copy of it */ #define EV_NOHOOK (1<<2) /* don't call hook when setting */ +#define EV_NOKENV (1<<3) /* don't add to kenv (loader-only) */ struct env_var; typedef char *(ev_format_t)(struct env_var *ev); @@ -499,6 +508,9 @@ extern void *reallocf(void *, size_t); */ caddr_t ptov(uintptr_t); +/* dev_net.c */ +bool is_tftp(void); + /* features.c */ typedef void (feature_iter_fn)(void *, const char *, const char *, bool); @@ -558,4 +570,17 @@ void tslog_getbuf(void ** buf, size_t * len); __END_DECLS +/* define _DEBUG_LEVEL n or _DEBUG_LEVEL_VAR before include */ +#ifndef DEBUG_PRINTF +# if defined(_DEBUG_LEVEL) || defined(_DEBUG_LEVEL_VAR) +# ifndef _DEBUG_LEVEL_VAR +# define _DEBUG_LEVEL_VAR _debug +static int _debug = _DEBUG_LEVEL; +# endif +# define DEBUG_PRINTF(n, args) if (_DEBUG_LEVEL_VAR >= n) printf args +# else +# define DEBUG_PRINTF(n, args) +# endif +#endif + #endif /* STAND_H */ diff --git a/stand/libsa/tftp.c b/stand/libsa/tftp.c index c6cc8f11a765..656c402683bb 100644 --- a/stand/libsa/tftp.c +++ b/stand/libsa/tftp.c @@ -50,6 +50,10 @@ #include <netinet/in_systm.h> #include <arpa/tftp.h> +#ifdef LOADER_VERIEXEC +#include <verify_file.h> +#endif + #include <string.h> #include "stand.h" @@ -73,6 +77,7 @@ static int tftp_preload(struct open_file *); struct fs_ops tftp_fsops = { .fs_name = "tftp", + .fs_flags = 0, .fo_open = tftp_open, .fo_close = tftp_close, .fo_read = tftp_read, @@ -84,7 +89,6 @@ struct fs_ops tftp_fsops = { }; static int tftpport = 2000; -static int is_open = 0; /* * The legacy TFTP_BLKSIZE value was SEGSIZE(512). @@ -98,10 +102,14 @@ static int is_open = 0; * Jumbo frames in the future. */ #define TFTP_MAX_BLKSIZE 9008 -#define TFTP_TRIES 2 +#define TFTP_TRIES 3 struct tftp_handle { struct iodesc *iodesc; + struct iodesc io; + int id; + ino_t ino; + int port; int currblock; /* contents of lastdata */ unsigned int islastblock:1; /* flag */ unsigned int tries:4; /* number of read attempts */ @@ -177,6 +185,9 @@ tftp_sendack(struct tftp_handle *h, u_short block) wbuf.t.th_block = htons(block); wtail += 2; + DEBUG_PRINTF(5,("%s: myport=%hu xid=%lu, block=%hu\n", + __func__, h->iodesc->myport, h->iodesc->xid, block)); + sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); } @@ -190,6 +201,7 @@ recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *ptr = NULL; ssize_t len; int tftp_error; + unsigned short block; errno = 0; extra = recv_extra; @@ -203,19 +215,22 @@ recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, } extra->rtype = ntohs(t->th_opcode); - switch (ntohs(t->th_opcode)) { + block = ntohs(t->th_block); + DEBUG_PRINTF(6,("%s: myport=%hu xid=%lu, block=%hu, opcode=%hu\n", + __func__, d->myport, d->xid, block, extra->rtype)); + switch (extra->rtype) { case DATA: { int got; - if (htons(t->th_block) < (u_short)d->xid) { + if (block < (u_short)d->xid) { /* * Apparently our ACK was missed, re-send. */ - tftp_sendack(h, htons(t->th_block)); + tftp_sendack(h, block); free(ptr); return (-1); } - if (htons(t->th_block) != (u_short)d->xid) { + if (block != (u_short)d->xid) { /* * Packet from the future, drop this. */ @@ -241,9 +256,7 @@ recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, printf("illegal tftp error %d\n", tftp_error); errno = EIO; } else { -#ifdef TFTP_DEBUG - printf("tftp-error %d\n", tftp_error); -#endif + DEBUG_PRINTF(0, ("tftp-error %d\n", tftp_error)); errno = tftperrors[tftp_error]; } free(ptr); @@ -284,9 +297,7 @@ recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, return (0); } default: -#ifdef TFTP_DEBUG - printf("tftp type %d not handled\n", ntohs(t->th_opcode)); -#endif + DEBUG_PRINTF(0, ("tftp type %hu not handled\n", extra->rtype)); free(ptr); return (-1); } @@ -343,7 +354,7 @@ tftp_makereq(struct tftp_handle *h) bcopy("0", wtail, 2); wtail += 2; - h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); + h->iodesc->myport = htons(h->port + (getsecs() & 0x3ff)); h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->xid = 1; /* expected block */ @@ -351,11 +362,15 @@ tftp_makereq(struct tftp_handle *h) h->islastblock = 0; h->validsize = 0; + DEBUG_PRINTF(5,("%s: %s: id=%d port=%d myport=%hu xid=1\n", + __func__, h->path, h->id, h->port, ntohs(h->iodesc->myport))); pkt = NULL; recv_extra.tftp_handle = h; res = sendrecv(h->iodesc, &sendudp, &wbuf.t, wtail - (char *)&wbuf.t, &recvtftp, &pkt, (void **)&t, &recv_extra); if (res == -1) { + DEBUG_PRINTF(3,("%s: %s: id=%d errno=%d\n", + __func__, h->path, h->id, errno)); free(pkt); return (errno); } @@ -410,12 +425,18 @@ tftp_getnextblock(struct tftp_handle *h) h->iodesc->xid = h->currblock + 1; /* expected block */ + DEBUG_PRINTF(5,("%s: %s: id=%d port=%d myport=%hu xid=%lu\n", + __func__, h->path, h->id, h->port, + ntohs(h->iodesc->myport), h->iodesc->xid)); + pkt = NULL; recv_extra.tftp_handle = h; res = sendrecv(h->iodesc, &sendudp, &wbuf.t, wtail - (char *)&wbuf.t, &recvtftp, &pkt, (void **)&t, &recv_extra); if (res == -1) { /* 0 is OK! */ + DEBUG_PRINTF(3,("%s: %s: id=%d errno=%d\n", + __func__, h->path, h->id, errno)); free(pkt); return (errno); } @@ -428,21 +449,32 @@ tftp_getnextblock(struct tftp_handle *h) if (res < h->tftp_blksize) h->islastblock = 1; /* EOF */ - if (h->islastblock == 1) { + DEBUG_PRINTF(5,("%s: %s: id=%d res=%d blksz=%d last=%d\n", + __func__, h->path, h->id, res, h->tftp_blksize, h->islastblock)); + + if (h->islastblock) { /* Send an ACK for the last block */ - wbuf.t.th_block = htons((u_short)h->currblock); - sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); + tftp_sendack(h, h->currblock); } return (0); } +/* + * If doing verification we need to handle multiple + * files at the same time. + */ +#define TOPEN_MAX 8 +static struct tftp_handle *handles[TOPEN_MAX]; + static int tftp_open(const char *path, struct open_file *f) { struct devdesc *dev; struct tftp_handle *tftpfile; struct iodesc *io; + static int lx = 0; + int i, x; int res; size_t pathsize; const char *extraslash; @@ -450,24 +482,39 @@ tftp_open(const char *path, struct open_file *f) if (netproto != NET_TFTP) return (EINVAL); - if (f->f_dev->dv_type != DEVT_NET) + if (f->f_dev == NULL || f->f_dev->dv_type != DEVT_NET) return (EINVAL); - if (is_open) + tftpfile = NULL; + for (x = lx + 1, i = 0; i < TOPEN_MAX; i++, x++) { + x %= TOPEN_MAX; + if (handles[x] == NULL) { + handles[x] = tftpfile = calloc(1, sizeof(*tftpfile)); + if (tftpfile == NULL) + return (ENOMEM); + /* id allows us to clear the slot on close */ + tftpfile->id = lx = x; + /* port ensures a different session with server */ + tftpfile->port = (tftpport + (x * tftpport)) & 0xffff; + DEBUG_PRINTF(1, ("%s(%s) id=%d port=%d\n", + __func__, path, tftpfile->id, tftpfile->port)); + break; + } + } + if (tftpfile == NULL) { + DEBUG_PRINTF(1, ("%s: EBUSY\n", __func__)); return (EBUSY); - - tftpfile = calloc(1, sizeof(*tftpfile)); - if (!tftpfile) - return (ENOMEM); - + } tftpfile->tftp_blksize = TFTP_REQUESTED_BLKSIZE; dev = f->f_devdata; - tftpfile->iodesc = io = socktodesc(*(int *)(dev->d_opendata)); + io = socktodesc(*(int *)(dev->d_opendata)); if (io == NULL) { free(tftpfile); return (EINVAL); } + memcpy(&tftpfile->io, io, sizeof(tftpfile->io)); + io = tftpfile->iodesc = &tftpfile->io; io->destip = rootip; tftpfile->off = 0; pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof(char); @@ -480,8 +527,11 @@ tftp_open(const char *path, struct open_file *f) extraslash = ""; else extraslash = "/"; - res = snprintf(tftpfile->path, pathsize, "%s%s%s", - rootpath, extraslash, path); + if (rootpath[0] == '/' && rootpath[1] == '\0' && path[0] == '/') + res = strlcpy(tftpfile->path, path, pathsize); + else + res = snprintf(tftpfile->path, pathsize, "%s%s%s", + rootpath, extraslash, path); if (res < 0 || res > pathsize) { free(tftpfile->path); free(tftpfile); @@ -491,13 +541,13 @@ tftp_open(const char *path, struct open_file *f) res = tftp_makereq(tftpfile); if (res) { + handles[tftpfile->id] = NULL; free(tftpfile->path); free(tftpfile->pkt); free(tftpfile); return (res); } f->f_fsdata = tftpfile; - is_open = 1; return (0); } @@ -547,9 +597,7 @@ tftp_read(struct open_file *f, void *addr, size_t size, rc = tftp_getnextblock(tftpfile); if (rc) { /* no answer */ -#ifdef TFTP_DEBUG - printf("tftp: read error\n"); -#endif + DEBUG_PRINTF(0, ("tftp: read error\n")); if (tftpfile->tries > TFTP_TRIES) { return (rc); } else { @@ -568,10 +616,8 @@ tftp_read(struct open_file *f, void *addr, size_t size, inbuffer = tftpfile->validsize - offinblock; if (inbuffer < 0) { -#ifdef TFTP_DEBUG - printf("tftp: invalid offset %d\n", - tftpfile->off); -#endif + DEBUG_PRINTF(0, ("tftp: invalid offset %d\n", + tftpfile->off)); return (EINVAL); } count = (size < inbuffer ? size : inbuffer); @@ -586,15 +632,15 @@ tftp_read(struct open_file *f, void *addr, size_t size, if ((tftpfile->islastblock) && (count == inbuffer)) break; /* EOF */ } else { -#ifdef TFTP_DEBUG - printf("tftp: block %d not found\n", needblock); -#endif + DEBUG_PRINTF(0, ("tftp: block %d not found\n", needblock)); return (EINVAL); } } out: + DEBUG_PRINTF(4, ("%s(%s) res=%ld\n", __func__, tftpfile->path, + (tftpfile->tftp_tsize - tftpfile->off))); if (resid != NULL) *resid = res; return (rc); @@ -610,15 +656,18 @@ tftp_close(struct open_file *f) tftp_senderr(tftpfile, 0, "No error: file closed"); if (tftpfile) { + DEBUG_PRINTF(1, ("%s(%d): %s\n", __func__, + tftpfile->id, tftpfile->path)); + handles[tftpfile->id] = NULL; free(tftpfile->path); free(tftpfile->pkt); free(tftpfile->tftp_cache); free(tftpfile); } - is_open = 0; return (0); } + static int tftp_stat(struct open_file *f, struct stat *sb) { @@ -630,6 +679,29 @@ tftp_stat(struct open_file *f, struct stat *sb) sb->st_uid = 0; sb->st_gid = 0; sb->st_size = tftpfile->tftp_tsize; + sb->st_mtime = 0; +#ifdef LOADER_VERIEXEC + /* libsecureboot needs st_dev and st_ino at minimum; + * we need to fake something that will be close enough to + * unique. + */ + sb->st_dev = (dev_t)tftpfile->iodesc->destip.s_addr; + /* we don't want to compute this more than once */ + if (tftpfile->ino == 0) { + union { + unsigned char digest[SHA_DIGEST_LENGTH]; + ino_t ino; + } u; + + hash_string(tftpfile->path, 0, u.digest, sizeof(u.digest)); + + tftpfile->ino = u.ino & 0x7fffffff; + DEBUG_PRINTF(2,("%s(%s) dev=%lu ino=%lu\n", __func__, + tftpfile->path, (unsigned long)sb->st_dev, + (unsigned long)tftpfile->ino)); + } + sb->st_ino = tftpfile->ino; +#endif return (0); } @@ -827,9 +899,7 @@ tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) return (-1); } -#ifdef TFTP_DEBUG - printf("tftp_blksize: %u\n", h->tftp_blksize); - printf("tftp_tsize: %lu\n", h->tftp_tsize); -#endif + DEBUG_PRINTF(2, ("tftp_blksize: %u\n", h->tftp_blksize)); + DEBUG_PRINTF(2, ("tftp_tsize: %lu\n", h->tftp_tsize)); return (0); } diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c index e1d540ed2321..868e8d47dbbd 100644 --- a/stand/libsa/ufs.c +++ b/stand/libsa/ufs.c @@ -93,6 +93,7 @@ static int ufs_unmount(const char *dev, void *data); struct fs_ops ufs_fsops = { .fs_name = "ufs", + .fs_flags = 0, .fo_open = ufs_open, .fo_close = ufs_close, .fo_read = ufs_read, @@ -890,6 +891,12 @@ ufs_readdir(struct open_file *f, struct dirent *d) if (error) return (error); dp = (struct direct *)buf; + /* + * Check for corrupt directory entry and bail out rather + * than spin forever hoping that the user has other options. + */ + if (dp->d_reclen == 0) + return (0); fp->f_seekp += dp->d_reclen; } while (dp->d_ino == (ino_t)0); diff --git a/stand/libsa/ufsread.c b/stand/libsa/ufsread.c index 0f9b9bb4e2fb..86ac8fbbbab7 100644 --- a/stand/libsa/ufsread.c +++ b/stand/libsa/ufsread.c @@ -108,6 +108,13 @@ fsfind(const char *name, ufs_ino_t * ino) *ino = d.d_ino; return d.d_type; } + /* + * Check for corrupt directory entry and bail out + * rather than spin forever hoping that the user + * has other options. + */ + if (d.d_reclen == 0) + return 0; s += d.d_reclen; } if (n != -1 && ls) diff --git a/stand/libsa/zfs/spl/sys/zfs_context.h b/stand/libsa/zfs/spl/sys/zfs_context.h index 48f164317611..9f12955dd05f 100644 --- a/stand/libsa/zfs/spl/sys/zfs_context.h +++ b/stand/libsa/zfs/spl/sys/zfs_context.h @@ -20,7 +20,7 @@ #include_next <sys/zfs_context.h> -#define ZFS_MODULE_PARAM_ARGS void +#define SYSCTL_HANDLER_ARGS void /* * Not sure why I need these, but including the canonical stand.h fails because diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c index 41ef5a46f30e..f15d9b016068 100644 --- a/stand/libsa/zfs/zfsimpl.c +++ b/stand/libsa/zfs/zfsimpl.c @@ -107,11 +107,6 @@ typedef struct indirect_vsd { } indirect_vsd_t; /* - * List of all vdevs, chained through v_alllink. - */ -static vdev_list_t zfs_vdevs; - -/* * List of supported read-incompatible ZFS features. Do not add here features * marked as ZFEATURE_FLAG_READONLY_COMPAT, they are irrelevant for read-only! */ @@ -167,7 +162,6 @@ vdev_indirect_mapping_entry_phys_t * static void zfs_init(void) { - STAILQ_INIT(&zfs_vdevs); STAILQ_INIT(&zfs_pools); dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); @@ -839,16 +833,27 @@ vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, return (kid->v_read(kid, bp, buf, offset, bytes)); } +/* + * List of vdevs that were fully initialized from their own label, but later a + * newer label was found that obsoleted the stale label, freeing its + * configuration tree. We keep those vdevs around, since a new configuration + * may include them. + */ +static vdev_list_t orphans = STAILQ_HEAD_INITIALIZER(orphans); + static vdev_t * -vdev_find(uint64_t guid) +vdev_find(vdev_list_t *list, uint64_t guid) { - vdev_t *vdev; + vdev_t *vdev, *safe; - STAILQ_FOREACH(vdev, &zfs_vdevs, v_alllink) + STAILQ_FOREACH_SAFE(vdev, list, v_childlink, safe) { if (vdev->v_guid == guid) return (vdev); + if ((vdev = vdev_find(&vdev->v_children, guid)) != NULL) + return (vdev); + } - return (0); + return (NULL); } static vdev_t * @@ -857,6 +862,11 @@ vdev_create(uint64_t guid, vdev_read_t *_read) vdev_t *vdev; vdev_indirect_config_t *vic; + if ((vdev = vdev_find(&orphans, guid))) { + STAILQ_REMOVE(&orphans, vdev, vdev, v_childlink); + return (vdev); + } + vdev = calloc(1, sizeof(vdev_t)); if (vdev != NULL) { STAILQ_INIT(&vdev->v_children); @@ -871,7 +881,6 @@ vdev_create(uint64_t guid, vdev_read_t *_read) if (_read != NULL) { vic = &vdev->vdev_indirect_config; vic->vic_prev_indirect_vdev = UINT64_MAX; - STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); } } @@ -1035,22 +1044,19 @@ vdev_init(uint64_t guid, const nvlist_t *nvlist, vdev_t **vdevp) * STAILQ_INSERT_AFTER. */ static vdev_t * -vdev_find_previous(vdev_t *top_vdev, vdev_t *vdev) +vdev_find_previous(vdev_t *top_vdev, uint64_t id) { vdev_t *v, *previous; - if (STAILQ_EMPTY(&top_vdev->v_children)) - return (NULL); - previous = NULL; STAILQ_FOREACH(v, &top_vdev->v_children, v_childlink) { - if (v->v_id > vdev->v_id) + if (v->v_id > id) return (previous); - if (v->v_id == vdev->v_id) + if (v->v_id == id) return (v); - if (v->v_id < vdev->v_id) + if (v->v_id < id) previous = v; } return (previous); @@ -1072,7 +1078,7 @@ vdev_child_count(vdev_t *vdev) /* * Insert vdev into top_vdev children list. List is ordered by v_id. */ -static void +static vdev_t * vdev_insert(vdev_t *top_vdev, vdev_t *vdev) { vdev_t *previous; @@ -1085,7 +1091,7 @@ vdev_insert(vdev_t *top_vdev, vdev_t *vdev) * so we can use either STAILQ_INSERT_HEAD or STAILQ_INSERT_AFTER * as STAILQ does not have insert before. */ - previous = vdev_find_previous(top_vdev, vdev); + previous = vdev_find_previous(top_vdev, vdev->v_id); if (previous == NULL) { STAILQ_INSERT_HEAD(&top_vdev->v_children, vdev, v_childlink); @@ -1094,7 +1100,8 @@ vdev_insert(vdev_t *top_vdev, vdev_t *vdev) * This vdev was configured from label config, * do not insert duplicate. */ - return; + free(vdev); + return (previous); } else { STAILQ_INSERT_AFTER(&top_vdev->v_children, previous, vdev, v_childlink); @@ -1103,24 +1110,28 @@ vdev_insert(vdev_t *top_vdev, vdev_t *vdev) count = vdev_child_count(top_vdev); if (top_vdev->v_nchildren < count) top_vdev->v_nchildren = count; + return (vdev); } static int -vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist) +vdev_from_nvlist(spa_t *spa, uint64_t top_guid, uint64_t label_guid, + uint64_t txg, const nvlist_t *nvlist) { vdev_t *top_vdev, *vdev; nvlist_t **kids = NULL; int rc, nkids; /* Get top vdev. */ - top_vdev = vdev_find(top_guid); + top_vdev = vdev_find(&spa->spa_root_vdev->v_children, top_guid); if (top_vdev == NULL) { rc = vdev_init(top_guid, nvlist, &top_vdev); if (rc != 0) return (rc); top_vdev->v_spa = spa; top_vdev->v_top = top_vdev; - vdev_insert(spa->spa_root_vdev, top_vdev); + top_vdev->v_label = label_guid; + top_vdev->v_txg = txg; + (void )vdev_insert(spa->spa_root_vdev, top_vdev); } /* Add children if there are any. */ @@ -1141,7 +1152,7 @@ vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist) vdev->v_spa = spa; vdev->v_top = top_vdev; - vdev_insert(top_vdev, vdev); + vdev = vdev_insert(top_vdev, vdev); } } else { /* @@ -1160,28 +1171,6 @@ done: return (rc); } -static int -vdev_init_from_label(spa_t *spa, const nvlist_t *nvlist) -{ - uint64_t pool_guid, top_guid; - nvlist_t *vdevs; - int rc; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid, NULL) || - nvlist_find(nvlist, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64, - NULL, &top_guid, NULL) || - nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs, NULL)) { - printf("ZFS: can't find vdev details\n"); - return (ENOENT); - } - - rc = vdev_from_nvlist(spa, top_guid, vdevs); - nvlist_destroy(vdevs); - return (rc); -} - static void vdev_set_state(vdev_t *vdev) { @@ -1228,14 +1217,14 @@ vdev_set_state(vdev_t *vdev) } static int -vdev_update_from_nvlist(uint64_t top_guid, const nvlist_t *nvlist) +vdev_update_from_nvlist(vdev_t *root, uint64_t top_guid, const nvlist_t *nvlist) { vdev_t *vdev; nvlist_t **kids = NULL; int rc, nkids; /* Update top vdev. */ - vdev = vdev_find(top_guid); + vdev = vdev_find(&root->v_children, top_guid); if (vdev != NULL) vdev_set_initial_state(vdev, nvlist); @@ -1251,7 +1240,7 @@ vdev_update_from_nvlist(uint64_t top_guid, const nvlist_t *nvlist) if (rc != 0) break; - vdev = vdev_find(guid); + vdev = vdev_find(&root->v_children, guid); if (vdev != NULL) vdev_set_initial_state(vdev, kids[i]); } @@ -1267,6 +1256,19 @@ vdev_update_from_nvlist(uint64_t top_guid, const nvlist_t *nvlist) return (rc); } +static void +vdev_free(struct vdev *vdev) +{ + struct vdev *kid, *safe; + + STAILQ_FOREACH_SAFE(kid, &vdev->v_children, v_childlink, safe) + vdev_free(kid); + if (vdev->v_phys_read != NULL) + STAILQ_INSERT_HEAD(&orphans, vdev, v_childlink); + else + free(vdev); +} + static int vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) { @@ -1310,14 +1312,16 @@ vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) NULL, &guid, NULL); if (rc != 0) break; - vdev = vdev_find(guid); + vdev = vdev_find(&spa->spa_root_vdev->v_children, guid); /* * Top level vdev is missing, create it. + * XXXGL: how can this happen? */ if (vdev == NULL) - rc = vdev_from_nvlist(spa, guid, kids[i]); + rc = vdev_from_nvlist(spa, guid, 0, 0, kids[i]); else - rc = vdev_update_from_nvlist(guid, kids[i]); + rc = vdev_update_from_nvlist(spa->spa_root_vdev, guid, + kids[i]); if (rc != 0) break; } @@ -1335,6 +1339,53 @@ vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) return (rc); } +static bool +nvlist_find_child_guid(const nvlist_t *nvlist, uint64_t guid) +{ + nvlist_t **kids = NULL; + int nkids, i; + bool rv = false; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids, NULL) != 0) + nkids = 0; + + for (i = 0; i < nkids; i++) { + uint64_t kid_guid; + + if (nvlist_find(kids[i], ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &kid_guid, NULL) != 0) + break; + if (kid_guid == guid) + rv = true; + else + rv = nvlist_find_child_guid(kids[i], guid); + if (rv) + break; + } + + for (i = 0; i < nkids; i++) + nvlist_destroy(kids[i]); + free(kids); + + return (rv); +} + +static bool +nvlist_find_vdev_guid(const nvlist_t *nvlist, uint64_t guid) +{ + nvlist_t *vdevs; + bool rv; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, NULL, + &vdevs, NULL) != 0) + return (false); + rv = nvlist_find_child_guid(vdevs, guid); + nvlist_destroy(vdevs); + + return (rv); +} + static spa_t * spa_find_by_guid(uint64_t guid) { @@ -1379,7 +1430,7 @@ spa_create(uint64_t guid, const char *name) free(spa); return (NULL); } - spa->spa_root_vdev->v_name = strdup("root"); + spa->spa_root_vdev->v_name = spa->spa_name; STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); return (spa); @@ -2003,11 +2054,10 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, { vdev_t vtmp; spa_t *spa; - vdev_t *vdev; - nvlist_t *nvl; + vdev_t *vdev, *top; + nvlist_t *nvl, *vdevs; uint64_t val; - uint64_t guid, vdev_children; - uint64_t pool_txg, pool_guid; + uint64_t guid, pool_guid, top_guid, txg; const char *pool_name; int rc, namelen; @@ -2063,13 +2113,18 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, } if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, - NULL, &pool_txg, NULL) != 0 || + NULL, &txg, NULL) != 0 || + txg == 0 || + nvlist_find(nvl, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64, + NULL, &top_guid, NULL) != 0 || nvlist_find(nvl, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, NULL, &pool_guid, NULL) != 0 || nvlist_find(nvl, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, - NULL, &pool_name, &namelen) != 0) { + NULL, &pool_name, &namelen) != 0 || + nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid, NULL) != 0) { /* - * Cache and spare devices end up here - just ignore + * Cache, spare and replaced devices end up here - just ignore * them. */ nvlist_destroy(nvl); @@ -2083,8 +2138,6 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, if (spa == NULL) { char *name; - nvlist_find(nvl, ZPOOL_CONFIG_VDEV_CHILDREN, - DATA_TYPE_UINT64, NULL, &vdev_children, NULL); name = malloc(namelen + 1); if (name == NULL) { nvlist_destroy(nvl); @@ -2098,10 +2151,47 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, nvlist_destroy(nvl); return (ENOMEM); } - spa->spa_root_vdev->v_nchildren = vdev_children; } - if (pool_txg > spa->spa_txg) - spa->spa_txg = pool_txg; + + /* + * Check if configuration is already known. If configuration is known + * and txg numbers don't match, we got 2x2 scenarios here. First, is + * the label being read right now _newer_ than the one read before. + * Second, is the vdev that provided the stale label _present_ in the + * newer configuration. If neither is true, we completely ignore the + * label. + */ + STAILQ_FOREACH(top, &spa->spa_root_vdev->v_children, v_childlink) + if (top->v_guid == top_guid) { + bool newer, present; + + if (top->v_txg == txg) + break; + newer = (top->v_txg < txg); + present = newer ? + nvlist_find_vdev_guid(nvl, top->v_label) : + (vdev_find(&top->v_children, guid) != NULL); + printf("ZFS: pool %s vdev %s %s stale label from " + "0x%jx@0x%jx, %s 0x%jx@0x%jx\n", + spa->spa_name, top->v_name, + present ? "using" : "ignoring", + newer ? top->v_label : guid, + newer ? top->v_txg : txg, + present ? "referred by" : "using", + newer ? guid : top->v_label, + newer ? txg : top->v_txg); + if (newer) { + STAILQ_REMOVE(&spa->spa_root_vdev->v_children, + top, vdev, v_childlink); + vdev_free(top); + break; + } else if (present) { + break; + } else { + nvlist_destroy(nvl); + return (EIO); + } + } /* * Get the vdev tree and create our in-core copy of it. @@ -2109,19 +2199,22 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, * be some kind of alias (overlapping slices, dangerously dedicated * disks etc). */ - if (nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid, NULL) != 0) { - nvlist_destroy(nvl); - return (EIO); - } - vdev = vdev_find(guid); + vdev = vdev_find(&spa->spa_root_vdev->v_children, guid); /* Has this vdev already been inited? */ if (vdev && vdev->v_phys_read) { nvlist_destroy(nvl); return (EIO); } - rc = vdev_init_from_label(spa, nvl); + if (nvlist_find(nvl, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, NULL, + &vdevs, NULL)) { + printf("ZFS: can't find vdev details\n"); + nvlist_destroy(nvl); + return (ENOENT); + } + + rc = vdev_from_nvlist(spa, top_guid, guid, txg, vdevs); + nvlist_destroy(vdevs); nvlist_destroy(nvl); if (rc != 0) return (rc); @@ -2130,7 +2223,7 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, * We should already have created an incomplete vdev for this * vdev. Find it and initialise it with our read proc. */ - vdev = vdev_find(guid); + vdev = vdev_find(&spa->spa_root_vdev->v_children, guid); if (vdev != NULL) { vdev->v_phys_read = _read; vdev->v_phys_write = _write; @@ -3541,8 +3634,10 @@ zfs_spa_init(spa_t *spa) return (EIO); } rc = load_nvlist(spa, config_object, &nvlist); - if (rc != 0) + if (rc != 0) { + printf("ZFS: failed to load pool %s nvlist\n", spa->spa_name); return (rc); + } rc = zap_lookup(spa, &dir, DMU_POOL_ZPOOL_CHECKPOINT, sizeof(uint64_t), sizeof(checkpoint) / sizeof(uint64_t), diff --git a/stand/loader.mk b/stand/loader.mk index 0f2ff31a5343..e26ba1401912 100644 --- a/stand/loader.mk +++ b/stand/loader.mk @@ -89,7 +89,7 @@ SRCS+= interp_lua.c .include "${BOOTSRC}/lua.mk" LDR_INTERP= ${LIBLUA} LDR_INTERP32= ${LIBLUA32} -CFLAGS.interp_lua.c= -DLUA_PATH=\"${LUAPATH}\" -I${FLUASRC}/modules +CFLAGS.interp_lua.c= -DLUA_PATH=\"${LUAPATH}\" -I${FLUASRC}/lfs .elif ${LOADER_INTERP} == "4th" SRCS+= interp_forth.c .include "${BOOTSRC}/ficl.mk" @@ -101,8 +101,6 @@ SRCS+= interp_simple.c .error Unknown interpreter ${LOADER_INTERP} .endif -.include "${BOOTSRC}/veriexec.mk" - .if defined(BOOT_PROMPT_123) CFLAGS+= -DBOOT_PROMPT_123 .endif diff --git a/stand/lua/Makefile b/stand/lua/Makefile index 3cec7ae3b050..d319261e18b2 100644 --- a/stand/lua/Makefile +++ b/stand/lua/Makefile @@ -24,6 +24,7 @@ FILES= cli.lua \ gfx-beastie.lua \ gfx-beastiebw.lua \ gfx-fbsdbw.lua \ + gfx-install.lua \ gfx-orb.lua \ gfx-orbbw.lua \ menu.lua \ diff --git a/stand/lua/cli.lua b/stand/lua/cli.lua index 6832da0a31a5..dda8c3da4c89 100644 --- a/stand/lua/cli.lua +++ b/stand/lua/cli.lua @@ -30,18 +30,6 @@ local core = require("core") local cli = {} -if not pager then - -- shim for the pager module that just doesn't do it. - -- XXX Remove after 12.2 goes EoL. - pager = { - open = function() end, - close = function() end, - output = function(str) - printc(str) - end, - } -end - -- Internal function -- Parses arguments to boot and returns two values: kernel_name, argstr -- Defaults to nil and "" respectively. @@ -247,9 +235,17 @@ cli["disable-device"] = function(...) return end + if #argv > 1 then + print("Too many arguments") + print("usage error: disable-device device") + return + end + d, u = string.match(argv[1], "(%w*%a)(%d+)") - if d ~= nil then + if d ~= nil and u ~= nil then loader.setenv("hint." .. d .. "." .. u .. ".disabled", "1") + else + print("Cannot parse " .. argv[1] .." into driver and unit number.") end end diff --git a/stand/lua/cli.lua.8 b/stand/lua/cli.lua.8 index 4077ca6b0b56..e47ecd3d23db 100644 --- a/stand/lua/cli.lua.8 +++ b/stand/lua/cli.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 24, 2021 +.Dd March 29, 2025 .Dt CLI.LUA 8 .Os .Sh NAME .Nm cli.lua -.Nd FreeBSD Lua CLI module +.Nd bootloader command line interpreter module .Sh DESCRIPTION .Nm contains the main functionality required to add new CLI commands, which can be @@ -52,10 +52,11 @@ For instance: local cli = require("cli") cli.foo = function(...) - -- Expand args to command name and the rest of argv. These arguments - -- are pushed directly to the stack by loader, then handed off to - -- cli_execute. cli_execute then passes them on to the invoked - -- function, where they appear as varargs that must be peeled apart into + -- Expand args to command name and the rest of argv. + -- These arguments are pushed directly to the stack by + -- loader, then handed off to cli_execute. cli_execute + -- then passes them on to the invoked function, where + -- they appear as varargs that must be peeled apart into -- their respective components. local _, argv = cli.arguments(...) @@ -63,10 +64,11 @@ cli.foo = function(...) for k, v in ipairs(argv) do print("arg #" .. tostring(k) .. ": '" .. v .. "'") end - -- Perform a loader command directly. This will not get dispatched back - -- to Lua, so it is acceptable to have a function of the exact same name - -- in loader. Lua will have the first chance to handle any commands - -- executed at the loader prompt. + -- Perform a loader command directly. This will not get + -- dispatched back to Lua, so it is acceptable to have a + -- function of the exact same name in loader. Lua will + -- have the first chance to handle any commands executed + -- at the loader prompt. loader.perform("foo") end .Ed diff --git a/stand/lua/color.lua.8 b/stand/lua/color.lua.8 index 8a31d2034a48..9a3b9b1b9385 100644 --- a/stand/lua/color.lua.8 +++ b/stand/lua/color.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 19, 2018 +.Dd March 29, 2025 .Dt COLOR.LUA 8 .Os .Sh NAME .Nm color.lua -.Nd FreeBSD color module +.Nd bootloader color module .Sh DESCRIPTION .Nm contains functionality for working with colors. diff --git a/stand/lua/config.lua.8 b/stand/lua/config.lua.8 index b2b1122285eb..7e8863203446 100644 --- a/stand/lua/config.lua.8 +++ b/stand/lua/config.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 17, 2020 +.Dd March 29, 2025 .Dt CONFIG.LUA 8 .Os .Sh NAME .Nm config.lua -.Nd FreeBSD config module +.Nd bootloader configuration module .Sh DESCRIPTION .Nm contains configuration and module loading functionality. diff --git a/stand/lua/core.lua b/stand/lua/core.lua index 5976cc65156d..ad417e5f97e5 100644 --- a/stand/lua/core.lua +++ b/stand/lua/core.lua @@ -282,11 +282,11 @@ function core.kernelList() -- actually find any kernels, we just assume that they know what they're -- doing and leave it alone. if default_kernel and not present[default_kernel] and #kernels > 1 then - for i = 1, #kernels do - if i == #kernels then - kernels[i] = nil + for n = 1, #kernels do + if n == #kernels then + kernels[n] = nil else - kernels[i] = kernels[i + 1] + kernels[n] = kernels[n + 1] end end end @@ -413,7 +413,7 @@ end function core.isSingleUserBoot() local single_user = loader.getenv("boot_single") - return single_user ~= nil and single_user:lower() == "yes" + return single_user ~= nil and single_user:lower() ~= "no" end function core.isUEFIBoot() diff --git a/stand/lua/core.lua.8 b/stand/lua/core.lua.8 index 0bdf88c1a364..de43d3e2b220 100644 --- a/stand/lua/core.lua.8 +++ b/stand/lua/core.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 8, 2023 +.Dd March 29, 2025 .Dt CORE.LUA 8 .Os .Sh NAME .Nm core.lua -.Nd FreeBSD core module +.Nd bootloader core module .Sh DESCRIPTION .Nm contains core functionality that does not have a more fitting module. diff --git a/stand/lua/drawer.lua b/stand/lua/drawer.lua index 1bf741b2373e..1c03ed93f00a 100644 --- a/stand/lua/drawer.lua +++ b/stand/lua/drawer.lua @@ -101,6 +101,39 @@ local function processFile(gfxname) return true end +-- Backwards compatibility shims for previous FreeBSD versions, please document +-- new additions +local function adapt_fb_shim(def) + -- In FreeBSD 14.x+, we have improved framebuffer support in the loader + -- and some graphics may have images that we can actually draw on the + -- screen. Those graphics may come with shifts that are distinct from + -- the ASCII version, so we move both ascii and image versions into + -- their own tables. + if not def.ascii then + def.ascii = { + image = def.graphic, + requires_color = def.requires_color, + shift = def.shift, + } + end + if def.image then + assert(not def.fb, + "Unrecognized graphic definition format") + + -- Legacy images may have adapted a shift from the ASCII + -- version, or perhaps we just didn't care enough to adjust it. + -- Steal the shift. + def.fb = { + image = def.image, + width = def.image_rl, + shift = def.shift, + } + end + + def.adapted = true + return def +end + local function getBranddef(brand) if brand == nil then return nil @@ -123,6 +156,8 @@ local function getBranddef(brand) end branddef = branddefs[brand] + elseif not branddef.adapted then + adapt_fb_shim(branddef) end return branddef @@ -150,6 +185,8 @@ local function getLogodef(logo) end logodef = logodefs[logo] + elseif not logodef.adapted then + adapt_fb_shim(logodef) end return logodef @@ -166,6 +203,10 @@ local function drawmenu(menudef) local x = menu_position.x local y = menu_position.y + if string.lower(loader.getenv("loader_menu") or "") == "none" then + return + end + x = x + shift.x y = y + shift.y @@ -213,6 +254,13 @@ local function defaultframe() return "double" end +local function gfxenabled() + return (loader.getenv("loader_gfx") or "yes"):lower() ~= "no" +end +local function gfxcapable() + return core.isFramebufferConsole() and gfx.term_putimage +end + local function drawframe() local x = menu_position.x - 3 local y = menu_position.y - 1 @@ -238,7 +286,7 @@ local function drawframe() x = x + shift.x y = y + shift.y - if core.isFramebufferConsole() and gfx.term_drawrect ~= nil then + if gfxenabled() and gfxcapable() then gfx.term_drawrect(x, y, x + w, y + h) return true end @@ -276,6 +324,10 @@ local function drawbox() local menu_header_align = loader.getenv("loader_menu_title_align") local menu_header_x + if string.lower(loader.getenv("loader_menu") or "") == "none" then + return + end + x = x + shift.x y = y + shift.y @@ -315,22 +367,23 @@ local function drawbrand() branddef = getBranddef(drawer.default_brand) end - local graphic = branddef.graphic + local graphic = branddef.ascii.image x = x + shift.x y = y + shift.y - if branddef.shift ~= nil then - x = x + branddef.shift.x - y = y + branddef.shift.y - end - if core.isFramebufferConsole() and - gfx.term_putimage ~= nil and - branddef.image ~= nil then - if gfx.term_putimage(branddef.image, x, y, 0, 7, 0) - then + local gfx_requested = branddef.fb and gfxenabled() + if gfx_requested and gfxcapable() then + if branddef.fb.shift then + x = x + (branddef.fb.shift.x or 0) + y = y + (branddef.fb.shift.y or 0) + end + if gfx.term_putimage(branddef.fb.image, x, y, 0, 7, 0) then return true end + elseif branddef.ascii.shift then + x = x + (branddef.ascii.shift.x or 0) + y = y + (branddef.ascii.shift.y or 0) end draw(x, y, graphic) end @@ -346,8 +399,8 @@ local function drawlogo() local logodef = getLogodef(logo) - if logodef == nil or logodef.graphic == nil or - (not colored and logodef.requires_color) then + if logodef == nil or logodef.ascii == nil or + (not colored and logodef.ascii.requires_color) then -- Choose a sensible default if colored then logodef = getLogodef(drawer.default_color_logodef) @@ -361,7 +414,10 @@ local function drawlogo() end end - if logodef ~= nil and logodef.graphic == none then + -- This is a special little hack for the "none" logo to re-align the + -- menu and the brand to avoid having a lot of extraneous whitespace on + -- the right side. + if logodef and logodef.ascii.image == none then shift = logodef.shift else shift = default_shift @@ -370,25 +426,23 @@ local function drawlogo() x = x + shift.x y = y + shift.y - if logodef ~= nil and logodef.shift ~= nil then - x = x + logodef.shift.x - y = y + logodef.shift.y - end - - if core.isFramebufferConsole() and - gfx.term_putimage ~= nil and - logodef.image ~= nil then - local y1 = 15 + local gfx_requested = logodef.fb and gfxenabled() + if gfx_requested and gfxcapable() then + local y1 = logodef.fb.width or 15 - if logodef.image_rl ~= nil then - y1 = logodef.image_rl + if logodef.fb.shift then + x = x + (logodef.fb.shift.x or 0) + y = y + (logodef.fb.shift.y or 0) end - if gfx.term_putimage(logodef.image, x, y, 0, y + y1, 0) - then + if gfx.term_putimage(logodef.fb.image, x, y, 0, y + y1, 0) then return true end + elseif logodef.ascii.shift then + x = x + (logodef.ascii.shift.x or 0) + y = y + (logodef.ascii.shift.y or 0) end - draw(x, y, logodef.graphic) + + draw(x, y, logodef.ascii.image) end local function drawitem(func) @@ -445,11 +499,15 @@ branddefs = { -- Indexed by valid values for loader_brand in loader.conf(5). Valid -- keys are: graphic (table depicting graphic) ["fbsd"] = { - graphic = fbsd_brand, - image = "/boot/images/freebsd-brand-rev.png", + ascii = { + image = fbsd_brand, + }, + fb = { + image = "/boot/images/freebsd-brand-rev.png", + }, }, ["none"] = { - graphic = none, + ascii = { image = none }, }, } @@ -458,13 +516,19 @@ logodefs = { -- are: requires_color (boolean), graphic (table depicting graphic), and -- shift (table containing x and y). ["tribute"] = { - graphic = fbsd_brand, + ascii = { + image = fbsd_brand, + }, }, ["tributebw"] = { - graphic = fbsd_brand, + ascii = { + image = fbsd_brand, + }, }, ["none"] = { - graphic = none, + ascii = { + image = none, + }, shift = {x = 17, y = 0}, }, } @@ -484,14 +548,12 @@ drawer.default_bw_logodef = 'orbbw' -- drawer module in case it's a filesystem issue. drawer.default_fallback_logodef = 'none' --- These should go away after FreeBSD 13; only available for backwards --- compatibility with old logo- files. function drawer.addBrand(name, def) - branddefs[name] = def + branddefs[name] = adapt_fb_shim(def) end function drawer.addLogo(name, def) - logodefs[name] = def + logodefs[name] = adapt_fb_shim(def) end drawer.frame_styles = { diff --git a/stand/lua/drawer.lua.8 b/stand/lua/drawer.lua.8 index a3a4865d3efe..91738f4b2434 100644 --- a/stand/lua/drawer.lua.8 +++ b/stand/lua/drawer.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 19, 2018 +.Dd March 29, 2025 .Dt DRAWER.LUA 8 .Os .Sh NAME .Nm drawer.lua -.Nd FreeBSD menu/screen drawer module +.Nd bootloader menu/screen drawer module .Sh DESCRIPTION .Nm contains functionality for drawing and manipulating the menu, logo, and brand diff --git a/stand/lua/gfx-beastie.lua b/stand/lua/gfx-beastie.lua index 443f0fd888ba..f91e70667dac 100644 --- a/stand/lua/gfx-beastie.lua +++ b/stand/lua/gfx-beastie.lua @@ -49,5 +49,6 @@ return { " `--{__________)\027[m", }, requires_color = true, + shift = {x = 2, y = -5}, } } diff --git a/stand/lua/gfx-beastiebw.lua b/stand/lua/gfx-beastiebw.lua index c71e53a9c4e3..84e3dc6997df 100644 --- a/stand/lua/gfx-beastiebw.lua +++ b/stand/lua/gfx-beastiebw.lua @@ -48,5 +48,6 @@ return { " ,' ,-----' |", " `--{__________)", }, + shift = {x = 2, y = -5}, } } diff --git a/stand/lua/gfx-fbsdbw.lua b/stand/lua/gfx-fbsdbw.lua index 470af71a07b5..df3b6c856eef 100644 --- a/stand/lua/gfx-fbsdbw.lua +++ b/stand/lua/gfx-fbsdbw.lua @@ -42,6 +42,6 @@ return { " | | | |", " |____/|_____/|_____/", }, - shift = {x = 5, y = 4}, + shift = {x = 7, y = -1}, } } diff --git a/stand/lua/gfx-install.lua b/stand/lua/gfx-install.lua new file mode 100644 index 000000000000..d4cd34e32e1e --- /dev/null +++ b/stand/lua/gfx-install.lua @@ -0,0 +1,24 @@ +-- +-- Copyright (c) 2025 Joseph Mingrone <jrm@FreeBSD.org> +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- + +return { + brand = { + ascii = { + image = { + " _____ ____ ____ ____ ___ _ _ _", + "| ___| __ ___ ___| __ ) ___|| _ \\ |_ _|_ __ ___| |_ __ _| | | ___ _ __", + "| |_ | '__/ _ \\/ _ \\ _ \\___ \\| | | | | || '_ \\/ __| __/ _` | | |/ _ \\ '__|", + "| _|| | | __/ __/ |_) |__) | |_| | | || | | \\__ \\ || (_| | | | __/ |", + "|_| |_| \\___|\\___|____/____/|____/ |___|_| |_|___/\\__\\__,_|_|_|\\___|_|", + }, + requires_color = false, + }, + fb = { + image = "/boot/images/freebsd-install-brand-rev.png", + width = 80, + }, + } +} diff --git a/stand/lua/gfx-orb.lua b/stand/lua/gfx-orb.lua index cd834a2d6b8e..6845d6fa07bb 100644 --- a/stand/lua/gfx-orb.lua +++ b/stand/lua/gfx-orb.lua @@ -27,7 +27,8 @@ return { logo = { - graphic = { + ascii = { + image = { " \027[31m``` \027[31;1m`\027[31m", " s` `.....---...\027[31;1m....--.``` -/\027[31m", " +o .--` \027[31;1m/y:` +.\027[31m", @@ -43,10 +44,14 @@ return { " `:` \027[31;1m`:`", " \027[31;1m.-- `--.", " .---.....----.\027[m", + }, + requires_color = true, + shift = {x = 5, y = -1}, + }, + fb = { + image = "/boot/images/freebsd-logo-rev.png", + width = 15, + shift = {x = 2, y = -2}, }, - requires_color = true, - shift = {x = 2, y = -1}, - image = "/boot/images/freebsd-logo-rev.png", - image_rl = 15 } } diff --git a/stand/lua/gfx-orbbw.lua b/stand/lua/gfx-orbbw.lua index a97174a6a5a4..135ff806b67c 100644 --- a/stand/lua/gfx-orbbw.lua +++ b/stand/lua/gfx-orbbw.lua @@ -27,23 +27,25 @@ return { logo = { - graphic = { - " ``` `", - " s` `.....---.......--.``` -/", - " +o .--` /y:` +.", - " yo`:. :o `+-", - " y/ -/` -o/", - " .- ::/sy+:.", - " / `-- /", - " `: :`", - " `: :`", - " / /", - " .- -.", - " -- -.", - " `:` `:`", - " .-- `--.", - " .---.....----.", + ascii = { + image = { + " ``` `", + " s` `.....---.......--.``` -/", + " +o .--` /y:` +.", + " yo`:. :o `+-", + " y/ -/` -o/", + " .- ::/sy+:.", + " / `-- /", + " `: :`", + " `: :`", + " / /", + " .- -.", + " -- -.", + " `:` `:`", + " .-- `--.", + " .---.....----.", + }, + shift = {x = 2, y = -1}, }, - shift = {x = 2, y = -1}, } } diff --git a/stand/lua/gfx.lua.8 b/stand/lua/gfx.lua.8 index 82d3f90f4af7..75f258026804 100644 --- a/stand/lua/gfx.lua.8 +++ b/stand/lua/gfx.lua.8 @@ -3,12 +3,12 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd February 6, 2024 +.Dd March 29, 2025 .Dt GFX.LUA 8 .Os .Sh NAME .Nm gfx.lua -.Nd Fx Lua gfx module +.Nd bootloader graphics module .Sh DESCRIPTION The built-in graphics related Lua bindings for the .Fx diff --git a/stand/lua/hook.lua.8 b/stand/lua/hook.lua.8 index f0e20153a924..91d5f76b6e1c 100644 --- a/stand/lua/hook.lua.8 +++ b/stand/lua/hook.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 28, 2020 +.Dd March 29, 2025 .Dt HOOK.LUA 8 .Os .Sh NAME .Nm hook.lua -.Nd FreeBSD hook module +.Nd bootloader hook module .Sh DESCRIPTION .Nm contains functionality for defining hook types and attaching hooks. diff --git a/stand/lua/loader.conf.lua.5 b/stand/lua/loader.conf.lua.5 index 7fad7d2f78dd..509944ab6598 100644 --- a/stand/lua/loader.conf.lua.5 +++ b/stand/lua/loader.conf.lua.5 @@ -29,7 +29,7 @@ .Os .Sh NAME .Nm loader.conf.lua -.Nd Lua-based system bootstrap configuration file +.Nd system bootstrap Lua configuration information .Sh DESCRIPTION When the lua-based .Xr loader 8 diff --git a/stand/lua/loader.lua.8 b/stand/lua/loader.lua.8 index e5aee7e8602d..ffee46526c9f 100644 --- a/stand/lua/loader.lua.8 +++ b/stand/lua/loader.lua.8 @@ -3,12 +3,12 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd February 6, 2024 +.Dd March 29, 2025 .Dt LOADER.LUA 8 .Os .Sh NAME .Nm loader.lua -.Nd Fx Lua loader module +.Nd bootloader Lua binding module .Sh DESCRIPTION The built-in Lua bindings for the .Fx diff --git a/stand/lua/menu.lua b/stand/lua/menu.lua index 7c36b6c8d3c8..fb0645eb46ba 100644 --- a/stand/lua/menu.lua +++ b/stand/lua/menu.lua @@ -541,6 +541,7 @@ end function menu.autoboot(delay) local x = loader.getenv("loader_menu_timeout_x") or 4 local y = loader.getenv("loader_menu_timeout_y") or 24 + local autoboot_show = loader.getenv("loader_autoboot_show") or "yes" local endtime = loader.time() + delay local time local last @@ -548,10 +549,12 @@ function menu.autoboot(delay) time = endtime - loader.time() if last == nil or last ~= time then last = time - screen.setcursor(x, y) - printc("Autoboot in " .. time .. - " seconds. [Space] to pause ") - screen.defcursor() + if autoboot_show == "yes" then + screen.setcursor(x, y) + printc("Autoboot in " .. time .. + " seconds. [Space] to pause ") + screen.defcursor() + end end if io.ischar() then local ch = io.getchar() diff --git a/stand/lua/menu.lua.8 b/stand/lua/menu.lua.8 index e2a0ff09ffd9..e2e32efdf3b4 100644 --- a/stand/lua/menu.lua.8 +++ b/stand/lua/menu.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 31, 2021 +.Dd March 29, 2025 .Dt MENU.LUA 8 .Os .Sh NAME .Nm menu.lua -.Nd FreeBSD dynamic menu boot module +.Nd bootloader dynamic menu module .Sh DESCRIPTION .Nm contains the main functionality required to build a dynamic menu system. diff --git a/stand/lua/password.lua.8 b/stand/lua/password.lua.8 index 1fbe395ab0db..34623c001206 100644 --- a/stand/lua/password.lua.8 +++ b/stand/lua/password.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 19, 2018 +.Dd March 29, 2025 .Dt PASSWORD.LUA 8 .Os .Sh NAME .Nm password.lua -.Nd FreeBSD password module +.Nd bootloader password module .Sh DESCRIPTION .Nm contains functionality for prompting for and checking passwords. diff --git a/stand/lua/screen.lua.8 b/stand/lua/screen.lua.8 index 691af5bf0758..a41ce6faf08b 100644 --- a/stand/lua/screen.lua.8 +++ b/stand/lua/screen.lua.8 @@ -24,12 +24,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 19, 2018 +.Dd March 29, 2025 .Dt SCREEN.LUA 8 .Os .Sh NAME .Nm screen.lua -.Nd FreeBSD screen manipulation module +.Nd bootloader screen manipulation module .Sh DESCRIPTION .Nm contains functionality for manipulating the screen. diff --git a/stand/man/boot1.efi.8 b/stand/man/boot1.efi.8 index b6135f8e0e12..2c882a595592 100644 --- a/stand/man/boot1.efi.8 +++ b/stand/man/boot1.efi.8 @@ -1,4 +1,6 @@ .\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 2020 Netflix, Inc .\" .\" Redistribution and use in source and binary forms, with or without diff --git a/stand/man/loader.8 b/stand/man/loader.8 index 4fc3bbb7cff0..234eabd571e0 100644 --- a/stand/man/loader.8 +++ b/stand/man/loader.8 @@ -1,3 +1,6 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 1999 Daniel C. Sobral .\" All rights reserved. .\" Copyright (c) 2021 Warner Losh <imp@FreeBSD.org> @@ -115,11 +118,11 @@ scripting language changed to Lua by default in The .Nm was written by -.An Michael Smith Aq msmith@FreeBSD.org . +.An Michael Smith Aq Mt msmith@FreeBSD.org . .Pp FICL was written by -.An John Sadler Aq john_sadler@alum.mit.edu . +.An John Sadler Aq Mt john_sadler@alum.mit.edu . .Pp -.An Warner Losh Aq imp@FreeBSD.org +.An Warner Losh Aq Mt imp@FreeBSD.org integrated Lua into the tree based on initial work done by Pedro Souza for the 2014 Google Summer of Code. diff --git a/stand/man/loader_4th.8 b/stand/man/loader_4th.8 index 9e87326f893b..21e907bd8630 100644 --- a/stand/man/loader_4th.8 +++ b/stand/man/loader_4th.8 @@ -1,3 +1,6 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 1999 Daniel C. Sobral .\" All rights reserved. .\" @@ -576,8 +579,8 @@ first appeared in The .Nm was written by -.An Michael Smith Aq msmith@FreeBSD.org . +.An Michael Smith Aq Mt msmith@FreeBSD.org . .Pp .Tn FICL was written by -.An John Sadler Aq john_sadler@alum.mit.edu . +.An John Sadler Aq Mt john_sadler@alum.mit.edu . diff --git a/stand/man/loader_lua.8 b/stand/man/loader_lua.8 index 0aa467237266..c60de9417abc 100644 --- a/stand/man/loader_lua.8 +++ b/stand/man/loader_lua.8 @@ -1,3 +1,6 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 1999 Daniel C. Sobral .\" All rights reserved. .\" diff --git a/stand/man/loader_simp.8 b/stand/man/loader_simp.8 index cdacd823b1a5..683ca8b2da5d 100644 --- a/stand/man/loader_simp.8 +++ b/stand/man/loader_simp.8 @@ -1,3 +1,6 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" .\" Copyright (c) 1999 Daniel C. Sobral .\" All rights reserved. .\" @@ -755,4 +758,4 @@ first appeared in The .Nm was written by -.An Michael Smith Aq msmith@FreeBSD.org . +.An Michael Smith Aq Mt msmith@FreeBSD.org . diff --git a/stand/powerpc/boot1.chrp/boot1.c b/stand/powerpc/boot1.chrp/boot1.c index cdacb05c31ce..1a546f3473e2 100644 --- a/stand/powerpc/boot1.chrp/boot1.c +++ b/stand/powerpc/boot1.chrp/boot1.c @@ -18,9 +18,11 @@ #include <sys/param.h> #include <sys/dirent.h> #include <sys/endian.h> +#include <sys/stdarg.h> + #include <machine/elf.h> -#include <machine/stdarg.h> #include <machine/md_var.h> + #include <ufs/ffs/fs.h> #include "paths.h" diff --git a/stand/powerpc/ofw/main.c b/stand/powerpc/ofw/main.c index e86a8275c8eb..093dda27ae04 100644 --- a/stand/powerpc/ofw/main.c +++ b/stand/powerpc/ofw/main.c @@ -35,9 +35,21 @@ #include <machine/asm.h> #include <machine/psl.h> -struct arch_switch archsw; /* MI/MD interface boundary */ +#ifdef CAS +static int ppc64_autoload(void); +#endif -extern char end[]; +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_getdev = ofw_getdev, + .arch_copyin = ofw_copyin, + .arch_copyout = ofw_copyout, + .arch_readin = ofw_readin, +#ifdef CAS + .arch_autoload = ppc64_autoload, +#else + .arch_autoload = ofw_autoload, +#endif +}; uint32_t acells, scells; @@ -165,15 +177,8 @@ main(int (*openfirm)(void *)) */ cons_probe(); - archsw.arch_getdev = ofw_getdev; - archsw.arch_copyin = ofw_copyin; - archsw.arch_copyout = ofw_copyout; - archsw.arch_readin = ofw_readin; #ifdef CAS setenv("cas", "1", 0); - archsw.arch_autoload = ppc64_autoload; -#else - archsw.arch_autoload = ofw_autoload; #endif /* Set up currdev variable to have hooks in place. */ diff --git a/stand/uboot/copy.c b/stand/uboot/copy.c index e5e985c85b27..7758e754666b 100644 --- a/stand/uboot/copy.c +++ b/stand/uboot/copy.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> - * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +35,7 @@ #include "libuboot.h" /* - * MD primitives supporting placement of module data + * MD primitives supporting placement of module data */ #ifdef __arm__ @@ -51,20 +51,17 @@ extern void _start(void); /* ubldr entry point address. */ +uint64_t loadbase; +bool loadbase_set = false; + /* * This is called for every object loaded (kernel, module, dtb file, etc). The * expected return value is the next address at or after the given addr which is * appropriate for loading the given object described by type and data. On each * call the addr is the next address following the previously loaded object. - * - * The first call is for loading the kernel, and the addr argument will be zero, - * and we search for a big block of ram to load the kernel and modules. - * - * On subsequent calls the addr will be non-zero, and we just round it up so - * that each object begins on a page boundary. */ -uint64_t -uboot_loadaddr(u_int type, void *data, uint64_t addr) +static uint64_t +uboot_loadaddr(void) { struct sys_info *si; uint64_t sblock, eblock, subldr, eubldr; @@ -73,87 +70,89 @@ uboot_loadaddr(u_int type, void *data, uint64_t addr) int i; char *envstr; - if (addr == 0) { - /* - * If the loader_kernaddr environment variable is set, blindly - * honor it. It had better be right. We force interpretation - * of the value in base-16 regardless of any leading 0x prefix, - * because that's the U-Boot convention. - */ - envstr = ub_env_get("loader_kernaddr"); - if (envstr != NULL) - return (strtoul(envstr, NULL, 16)); - - /* - * Find addr/size of largest DRAM block. Carve our own address - * range out of the block, because loading the kernel over the - * top ourself is a poor memory-conservation strategy. Avoid - * memory at beginning of the first block of physical ram, - * since u-boot likes to pass args and data there. Assume that - * u-boot has moved itself to the very top of ram and - * optimistically assume that we won't run into it up there. - */ - if ((si = ub_get_sys_info()) == NULL) - panic("could not retrieve system info"); - - biggest_block = 0; - biggest_size = 0; - subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); - eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); - for (i = 0; i < si->mr_no; i++) { - if (si->mr[i].flags != MR_ATTR_DRAM) - continue; - sblock = roundup2((uint64_t)si->mr[i].start, - KERN_ALIGN); - eblock = rounddown2((uint64_t)si->mr[i].start + - si->mr[i].size, KERN_ALIGN); - if (biggest_size == 0) - sblock += KERN_MINADDR; - if (subldr >= sblock && subldr < eblock) { - if (subldr - sblock > eblock - eubldr) { - this_block = sblock; - this_size = subldr - sblock; - } else { - this_block = eubldr; - this_size = eblock - eubldr; - } - } else if (subldr < sblock && eubldr < eblock) { - /* Loader is below or engulfs the sblock */ - this_block = (eubldr < sblock) ? sblock : eubldr; - this_size = eblock - this_block; + /* + * If the loader_kernaddr environment variable is set, blindly + * honor it. It had better be right. We force interpretation + * of the value in base-16 regardless of any leading 0x prefix, + * because that's the U-Boot convention. + */ + envstr = ub_env_get("loader_kernaddr"); + if (envstr != NULL) + return (strtoul(envstr, NULL, 16)); + + /* + * Find addr/size of largest DRAM block. Carve our own address + * range out of the block, because loading the kernel over the + * top ourself is a poor memory-conservation strategy. Avoid + * memory at beginning of the first block of physical ram, + * since u-boot likes to pass args and data there. Assume that + * u-boot has moved itself to the very top of ram and + * optimistically assume that we won't run into it up there. + */ + if ((si = ub_get_sys_info()) == NULL) + panic("could not retrieve system info"); + + biggest_block = 0; + biggest_size = 0; + subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); + eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); + for (i = 0; i < si->mr_no; i++) { + if (si->mr[i].flags != MR_ATTR_DRAM) + continue; + sblock = roundup2((uint64_t)si->mr[i].start, + KERN_ALIGN); + eblock = rounddown2((uint64_t)si->mr[i].start + + si->mr[i].size, KERN_ALIGN); + if (biggest_size == 0) + sblock += KERN_MINADDR; + if (subldr >= sblock && subldr < eblock) { + if (subldr - sblock > eblock - eubldr) { + this_block = sblock; + this_size = subldr - sblock; } else { - this_block = 0; - this_size = 0; - } - if (biggest_size < this_size) { - biggest_block = this_block; - biggest_size = this_size; + this_block = eubldr; + this_size = eblock - eubldr; } + } else if (subldr < sblock && eubldr < eblock) { + /* Loader is below or engulfs the sblock */ + this_block = (eubldr < sblock) ? sblock : eubldr; + this_size = eblock - this_block; + } else { + this_block = 0; + this_size = 0; } - if (biggest_size == 0) - panic("Not enough DRAM to load kernel"); + if (biggest_size < this_size) { + biggest_block = this_block; + biggest_size = this_size; + } + } + if (biggest_size == 0) + panic("Not enough DRAM to load kernel"); #if 0 - printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", - (uintmax_t)biggest_block, - (uintmax_t)biggest_block + biggest_size - 1, - (uintmax_t)biggest_size / 1024 / 1024); + printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", + (uintmax_t)biggest_block, + (uintmax_t)biggest_block + biggest_size - 1, + (uintmax_t)biggest_size / 1024 / 1024); #endif - return (biggest_block); - } - return roundup2(addr, PAGE_SIZE); + return (biggest_block); } ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len) { - bcopy(src, (void *)dest, len); + if (!loadbase_set) { + loadbase = uboot_loadaddr(); + loadbase_set = true; + } + + bcopy(src, (void *)(dest + loadbase), len); return (len); } ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len) { - bcopy((void *)src, dest, len); + bcopy((void *)(src + loadbase), dest, len); return (len); } diff --git a/stand/uboot/libuboot.h b/stand/uboot/libuboot.h index 4723600b0cee..49bfff3ada6f 100644 --- a/stand/uboot/libuboot.h +++ b/stand/uboot/libuboot.h @@ -57,7 +57,6 @@ extern struct devsw uboot_storage; extern uintptr_t uboot_heap_start; extern uintptr_t uboot_heap_end; -uint64_t uboot_loadaddr(u_int type, void *data, uint64_t addr); ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t uboot_readin(readin_handle_t fd, vm_offset_t dest, const size_t len); diff --git a/stand/uboot/main.c b/stand/uboot/main.c index 5a896959122e..6f53c83543ba 100644 --- a/stand/uboot/main.c +++ b/stand/uboot/main.c @@ -35,22 +35,25 @@ #include "glue.h" #include "libuboot.h" -#ifndef nitems -#define nitems(x) (sizeof((x)) / sizeof((x)[0])) -#endif - #ifndef HEAP_SIZE #define HEAP_SIZE (2 * 1024 * 1024) #endif struct uboot_devdesc currdev; -struct arch_switch archsw; /* MI/MD interface boundary */ +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_getdev = uboot_getdev, + .arch_copyin = uboot_copyin, + .arch_copyout = uboot_copyout, + .arch_readin = uboot_readin, + .arch_autoload = uboot_autoload, +}; + int devs_no; uintptr_t uboot_heap_start; uintptr_t uboot_heap_end; -struct device_type { +struct device_type { const char *name; int type; } device_types[] = { @@ -65,8 +68,6 @@ struct device_type { extern char end[]; -extern unsigned char _etext[]; -extern unsigned char _edata[]; extern unsigned char __bss_start[]; extern unsigned char __sbss_start[]; extern unsigned char __sbss_end[]; @@ -336,7 +337,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) *unit = -1; *slice = D_SLICEWILD; *partition = D_PARTWILD; -} +} static void print_disk_probe_info(void) @@ -365,7 +366,7 @@ print_disk_probe_info(void) } static int -probe_disks(int devidx, int load_type, int load_unit, int load_slice, +probe_disks(int devidx, int load_type, int load_unit, int load_slice, int load_partition) { int open_result, unit; @@ -480,13 +481,6 @@ main(int argc, char **argv) meminfo(); - archsw.arch_loadaddr = uboot_loadaddr; - archsw.arch_getdev = uboot_getdev; - archsw.arch_copyin = uboot_copyin; - archsw.arch_copyout = uboot_copyout; - archsw.arch_readin = uboot_readin; - archsw.arch_autoload = uboot_autoload; - /* Set up currdev variable to have hooks in place. */ env_setenv("currdev", EV_VOLATILE, "", uboot_setcurrdev, env_nounset); @@ -518,7 +512,7 @@ main(int argc, char **argv) if ((load_type == DEV_TYP_NONE || (load_type & DEV_TYP_STOR)) && strcmp(devsw[i]->dv_name, "disk") == 0) { - if (probe_disks(i, load_type, load_unit, load_slice, + if (probe_disks(i, load_type, load_unit, load_slice, load_partition) == 0) break; } @@ -634,7 +628,7 @@ handle_uboot_env_var(enum ubenv_action action, const char * var) * import the uboot variable ubname into the loader variable ldname, * otherwise the historical behavior is to import to uboot.ubname. */ - if (action == UBENV_IMPORT) { + if (action == UBENV_IMPORT) { len = strcspn(var, "="); if (len == 0) { printf("name cannot start with '=': '%s'\n", var); diff --git a/stand/uboot/uboot_disk.c b/stand/uboot/uboot_disk.c index 4f7b6ba06942..1f75f0f6da3c 100644 --- a/stand/uboot/uboot_disk.c +++ b/stand/uboot/uboot_disk.c @@ -33,7 +33,8 @@ #include <sys/param.h> #include <sys/disk.h> -#include <machine/stdarg.h> +#include <sys/stdarg.h> + #include <stand.h> #include "api_public.h" diff --git a/stand/userboot/userboot/Makefile b/stand/userboot/userboot/Makefile index a1ba1b4d700e..2a66c0e3f8fe 100644 --- a/stand/userboot/userboot/Makefile +++ b/stand/userboot/userboot/Makefile @@ -13,18 +13,30 @@ SHLIB_NAME= userboot_${LOADER_INTERP}.so STRIP= LIBDIR= /boot +.if ${MACHINE_CPUARCH} == "amd64" +USERBOOT_KERNEL_SUPPORT= yes +.else +USERBOOT_KERNEL_SUPPORT= no +.endif + .PATH: ${.CURDIR}/../userboot SRCS= autoload.c SRCS+= bcache.c +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= biossmap.c +.endif +.if ${USERBOOT_KERNEL_SUPPORT} == "yes" SRCS+= bootinfo.c SRCS+= bootinfo32.c SRCS+= bootinfo64.c +.endif SRCS+= conf.c SRCS+= copy.c SRCS+= devicename.c +.if ${USERBOOT_KERNEL_SUPPORT} == "yes" SRCS+= elf32_freebsd.c SRCS+= elf64_freebsd.c +.endif SRCS+= host.c SRCS+= main.c SRCS+= userboot_cons.c @@ -49,6 +61,10 @@ VERSION_FILE?= ${.CURDIR}/../userboot/version LINKS+= ${BINDIR}/${SHLIB_NAME} ${BINDIR}/userboot.so .endif +.if ${USERBOOT_KERNEL_SUPPORT} == "yes" +CFLAGS+= -DUSERBOOT_KERNEL_SUPPORT +.endif + .if ${MK_LOADER_ZFS} != "no" CFLAGS+= -DUSERBOOT_ZFS_SUPPORT HAVE_ZFS=yes diff --git a/stand/userboot/userboot/bootinfo32.c b/stand/userboot/userboot/bootinfo32.c index 750574912172..6ba76cc56479 100644 --- a/stand/userboot/userboot/bootinfo32.c +++ b/stand/userboot/userboot/bootinfo32.c @@ -99,14 +99,14 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); kfp = file_findfile(NULL, md_kerntype); if (kfp == NULL) @@ -123,7 +123,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t /* Figure out the size and location of the metadata */ *modulep = addr; size = md_copymodules(0, false); - kernend = roundup(addr + size, PAGE_SIZE); + kernend = md_align(addr + size); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ diff --git a/stand/userboot/userboot/bootinfo64.c b/stand/userboot/userboot/bootinfo64.c index d20202bf4fbb..3e289bbebba0 100644 --- a/stand/userboot/userboot/bootinfo64.c +++ b/stand/userboot/userboot/bootinfo64.c @@ -131,14 +131,14 @@ bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); + addr = md_align(addr); kfp = file_findfile(NULL, md_kerntype); if (kfp == NULL) @@ -152,7 +152,7 @@ bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) /* Figure out the size and location of the metadata */ *modulep = addr; size = md_copymodules(0, true); - kernend = roundup(addr + size, PAGE_SIZE); + kernend = md_align(addr + size); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ diff --git a/stand/userboot/userboot/conf.c b/stand/userboot/userboot/conf.c index abfd16c592e7..63f64cb97fbe 100644 --- a/stand/userboot/userboot/conf.c +++ b/stand/userboot/userboot/conf.c @@ -83,16 +83,20 @@ struct netif_driver *netif_drivers[] = { * Sort formats so that those that can detect based on arguments * rather than reading the file go first. */ +#if defined(__amd64__) extern struct file_format i386_elf; extern struct file_format i386_elf_obj; extern struct file_format amd64_elf; extern struct file_format amd64_elf_obj; +#endif struct file_format *file_formats[] = { +#if defined(__amd64__) &i386_elf, &i386_elf_obj, &amd64_elf, &amd64_elf_obj, +#endif NULL }; diff --git a/stand/userboot/userboot/main.c b/stand/userboot/userboot/main.c index cf1d9b12d69f..03f226c08bb9 100644 --- a/stand/userboot/userboot/main.c +++ b/stand/userboot/userboot/main.c @@ -55,7 +55,16 @@ void *callbacks_arg; static jmp_buf jb; -struct arch_switch archsw; /* MI/MD interface boundary */ +struct arch_switch archsw = { /* MI/MD interface boundary */ + .arch_autoload = userboot_autoload, + .arch_getdev = userboot_getdev, + .arch_copyin = userboot_copyin, + .arch_copyout = userboot_copyout, + .arch_readin = userboot_readin, +#if defined(USERBOOT_ZFS_SUPPORT) + .arch_zfs_probe = userboot_zfs_probe, +#endif +}; static void extract_currdev(void); static void check_interpreter(void); @@ -189,15 +198,6 @@ loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks) putenv(var); } - archsw.arch_autoload = userboot_autoload; - archsw.arch_getdev = userboot_getdev; - archsw.arch_copyin = userboot_copyin; - archsw.arch_copyout = userboot_copyout; - archsw.arch_readin = userboot_readin; -#if defined(USERBOOT_ZFS_SUPPORT) - archsw.arch_zfs_probe = userboot_zfs_probe; -#endif - /* * Initialise the block cache. Set the upper limit. */ @@ -205,6 +205,11 @@ loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks) devinit(); extract_currdev(); +#if !defined(USERBOOT_KERNEL_SUPPORT) + printf("WARNING: This userboot does not support loading a kernel\n"); + delay(1500000); +#endif + /* * Checking the interpreter isn't worth the overhead unless we * actually have the swap_interpreter callback, so we actually version |