aboutsummaryrefslogtreecommitdiff
path: root/stand
diff options
context:
space:
mode:
Diffstat (limited to 'stand')
-rw-r--r--stand/common/bootstrap.h13
-rw-r--r--stand/common/commands.c95
-rw-r--r--stand/common/console.c23
-rw-r--r--stand/common/dev_net.c95
-rw-r--r--stand/common/gfx_fb.c81
-rw-r--r--stand/common/gfx_fb.h1
-rw-r--r--stand/common/install.c5
-rw-r--r--stand/common/load_elf.c9
-rw-r--r--stand/common/load_elf_obj.c8
-rw-r--r--stand/common/md.c2
-rw-r--r--stand/common/metadata.c10
-rw-r--r--stand/common/misc.c13
-rw-r--r--stand/common/modinfo.c24
-rw-r--r--stand/common/modinfo.h1
-rw-r--r--stand/common/module.c22
-rwxr-xr-xstand/common/newvers.sh6
-rw-r--r--stand/defaults/loader.conf6
-rw-r--r--stand/defaults/loader.conf.523
-rw-r--r--stand/defs.mk4
-rw-r--r--stand/efi/acpica/acpi_detect.c69
-rw-r--r--stand/efi/acpica/include/acpi_detect.h41
-rw-r--r--stand/efi/boot1/boot1.c8
-rw-r--r--stand/efi/boot1/proto.c4
-rw-r--r--stand/efi/gptboot/proto.c4
-rw-r--r--stand/efi/include/amd64/pe.h2
-rw-r--r--stand/efi/include/i386/pe.h2
-rw-r--r--stand/efi/libefi/efi_console.c23
-rw-r--r--stand/efi/libefi/efinet.c2
-rw-r--r--stand/efi/loader/Makefile7
-rw-r--r--stand/efi/loader/arch/amd64/elf64_freebsd.c8
-rw-r--r--stand/efi/loader/arch/amd64/multiboot2.c2
-rw-r--r--stand/efi/loader/arch/amd64/trap.c5
-rw-r--r--stand/efi/loader/arch/arm/exec.c11
-rw-r--r--stand/efi/loader/arch/arm64/exec.c8
-rw-r--r--stand/efi/loader/arch/i386/elf64_freebsd.c9
-rw-r--r--stand/efi/loader/arch/riscv/exec.c12
-rw-r--r--stand/efi/loader/bootinfo.c17
-rw-r--r--stand/efi/loader/copy.c4
-rw-r--r--stand/efi/loader/efi_main.c2
-rw-r--r--stand/efi/loader/framebuffer.c7
-rw-r--r--stand/efi/loader/main.c103
-rw-r--r--stand/fdt/fdt_loader_cmd.c9
-rw-r--r--stand/ficl/loader.c3
-rw-r--r--stand/fonts/Makefile7
-rw-r--r--stand/i386/Makefile2
-rw-r--r--stand/i386/boot2/Makefile3
-rw-r--r--stand/i386/cdboot/Makefile1
-rw-r--r--stand/i386/cdboot/cdboot.821
-rw-r--r--stand/i386/common/bootargs.h2
-rw-r--r--stand/i386/gptboot/Makefile9
-rw-r--r--stand/i386/gptzfsboot/Makefile10
-rw-r--r--stand/i386/gptzfsboot/zfsboot.c (renamed from stand/i386/zfsboot/zfsboot.c)20
-rw-r--r--stand/i386/isoboot/Makefile9
-rw-r--r--stand/i386/libi386/Makefile1
-rw-r--r--stand/i386/libi386/biosacpi.c2
-rw-r--r--stand/i386/libi386/biosmemdisk.c140
-rw-r--r--stand/i386/libi386/biospci.c2
-rw-r--r--stand/i386/libi386/biospnp.c2
-rw-r--r--stand/i386/libi386/bootinfo32.c6
-rw-r--r--stand/i386/libi386/bootinfo64.c6
-rw-r--r--stand/i386/libi386/libi386.h2
-rw-r--r--stand/i386/libi386/vidconsole.c21
-rw-r--r--stand/i386/loader/Makefile5
-rw-r--r--stand/i386/loader/main.c43
-rw-r--r--stand/i386/zfsboot/Makefile92
-rw-r--r--stand/i386/zfsboot/Makefile.depend17
-rw-r--r--stand/i386/zfsboot/zfsboot.8130
-rw-r--r--stand/i386/zfsboot/zfsldr.S281
-rw-r--r--stand/images/Makefile3
-rw-r--r--stand/images/freebsd-install-brand-rev.pngbin0 -> 7724 bytes
-rw-r--r--stand/kboot/include/efi.h10
-rw-r--r--stand/kboot/include/util.h5
-rw-r--r--stand/kboot/kboot/arch/aarch64/exec.c14
-rw-r--r--stand/kboot/kboot/arch/aarch64/load_addr.c121
-rw-r--r--stand/kboot/kboot/arch/aarch64/tramp.S4
-rw-r--r--stand/kboot/kboot/arch/amd64/amd64_tramp.S56
-rw-r--r--stand/kboot/kboot/arch/amd64/elf64_freebsd.c46
-rw-r--r--stand/kboot/kboot/arch/amd64/load_addr.c215
-rw-r--r--stand/kboot/kboot/arch/powerpc64/kerneltramp.S2
-rw-r--r--stand/kboot/kboot/arch/powerpc64/ppc64_elf_freebsd.c17
-rw-r--r--stand/kboot/kboot/main.c104
-rw-r--r--stand/kboot/libkboot/Makefile2
-rw-r--r--stand/kboot/libkboot/arch/aarch64/host_syscall.S2
-rw-r--r--stand/kboot/libkboot/arch/amd64/host_syscall.S2
-rw-r--r--stand/kboot/libkboot/arch/powerpc64/host_syscall.S2
-rw-r--r--stand/kboot/libkboot/crt1.c3
-rw-r--r--stand/kboot/libkboot/dfk.c292
-rw-r--r--stand/kboot/libkboot/efi.c172
-rw-r--r--stand/kboot/libkboot/seg.c3
-rw-r--r--stand/kboot/libkboot/util.c13
-rw-r--r--stand/kshim/bsd_kernel.c5
-rw-r--r--stand/liblua/Makefile2
-rw-r--r--stand/liblua/lstd.h2
-rw-r--r--stand/libofw/ofw_disk.c3
-rw-r--r--stand/libofw/openfirm.c3
-rw-r--r--stand/libsa/Makefile2
-rw-r--r--stand/libsa/bootp.c78
-rw-r--r--stand/libsa/bzipfs.c1
-rw-r--r--stand/libsa/cd9660.c1
-rw-r--r--stand/libsa/dosfs.c1
-rw-r--r--stand/libsa/environment.c17
-rw-r--r--stand/libsa/ext2fs.c1
-rw-r--r--stand/libsa/globals.c1
-rw-r--r--stand/libsa/gzipfs.c1
-rw-r--r--stand/libsa/hexdump.c2
-rw-r--r--stand/libsa/ip.c304
-rw-r--r--stand/libsa/libsa.34
-rw-r--r--stand/libsa/mount.c5
-rw-r--r--stand/libsa/net.h1
-rw-r--r--stand/libsa/nfs.c1
-rw-r--r--stand/libsa/open.c41
-rw-r--r--stand/libsa/panic.c2
-rw-r--r--stand/libsa/pkgfs.c34
-rw-r--r--stand/libsa/printf.c7
-rw-r--r--stand/libsa/smbios.c11
-rw-r--r--stand/libsa/splitfs.c1
-rw-r--r--stand/libsa/stand.h25
-rw-r--r--stand/libsa/tftp.c154
-rw-r--r--stand/libsa/ufs.c7
-rw-r--r--stand/libsa/ufsread.c7
-rw-r--r--stand/libsa/zfs/spl/sys/zfs_context.h2
-rw-r--r--stand/libsa/zfs/zfsimpl.c245
-rw-r--r--stand/loader.mk4
-rw-r--r--stand/lua/Makefile1
-rw-r--r--stand/lua/cli.lua22
-rw-r--r--stand/lua/cli.lua.822
-rw-r--r--stand/lua/color.lua.84
-rw-r--r--stand/lua/config.lua.84
-rw-r--r--stand/lua/core.lua10
-rw-r--r--stand/lua/core.lua.84
-rw-r--r--stand/lua/drawer.lua138
-rw-r--r--stand/lua/drawer.lua.84
-rw-r--r--stand/lua/gfx-beastie.lua1
-rw-r--r--stand/lua/gfx-beastiebw.lua1
-rw-r--r--stand/lua/gfx-fbsdbw.lua2
-rw-r--r--stand/lua/gfx-install.lua24
-rw-r--r--stand/lua/gfx-orb.lua15
-rw-r--r--stand/lua/gfx-orbbw.lua36
-rw-r--r--stand/lua/gfx.lua.84
-rw-r--r--stand/lua/hook.lua.84
-rw-r--r--stand/lua/loader.conf.lua.52
-rw-r--r--stand/lua/loader.lua.84
-rw-r--r--stand/lua/menu.lua11
-rw-r--r--stand/lua/menu.lua.84
-rw-r--r--stand/lua/password.lua.84
-rw-r--r--stand/lua/screen.lua.84
-rw-r--r--stand/man/boot1.efi.82
-rw-r--r--stand/man/loader.89
-rw-r--r--stand/man/loader_4th.87
-rw-r--r--stand/man/loader_lua.83
-rw-r--r--stand/man/loader_simp.85
-rw-r--r--stand/powerpc/boot1.chrp/boot1.c4
-rw-r--r--stand/powerpc/ofw/main.c23
-rw-r--r--stand/uboot/copy.c149
-rw-r--r--stand/uboot/libuboot.h1
-rw-r--r--stand/uboot/main.c32
-rw-r--r--stand/uboot/uboot_disk.c3
-rw-r--r--stand/userboot/userboot/Makefile16
-rw-r--r--stand/userboot/userboot/bootinfo32.c6
-rw-r--r--stand/userboot/userboot/bootinfo64.c6
-rw-r--r--stand/userboot/userboot/conf.c4
-rw-r--r--stand/userboot/userboot/main.c25
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
new file mode 100644
index 000000000000..59d173d3f8b3
--- /dev/null
+++ b/stand/images/freebsd-install-brand-rev.png
Binary files differ
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